from __future__ import annotations

from datetime import date

from fastapi import APIRouter, Depends, Header, HTTPException, Query
from pydantic import BaseModel, Field
from sqlmodel import Session, select

from app.db.session import get_session
from app.models import GeoChallengeTarget
from app.services.admin_auth import get_admin_session
from app.services.challenges import create_geo_attempt, leaderboard, players, today_geo, weekly_convert

router = APIRouter(tags=["challenges"])


def require_admin(
    x_admin_session: str | None = Header(default=None, alias="X-Admin-Session"),
    session: Session = Depends(get_session),
) -> None:
    get_admin_session(session, x_admin_session)


class GeoAttemptRequest(BaseModel):
    player_id: int
    target_id: int
    selected_x_percent: float = Field(ge=0, le=100)
    selected_y_percent: float = Field(ge=0, le=100)


class TargetCreate(BaseModel):
    name: str = Field(min_length=1, max_length=120)
    target_type: str = Field(default="city", max_length=32)
    latitude: float
    longitude: float
    x_percent: float = Field(default=50.0, ge=0, le=100)
    y_percent: float = Field(default=50.0, ge=0, le=100)
    canton: str | None = None
    difficulty: int = Field(default=1, ge=1, le=5)
    info_text: str = ""
    active: bool = True
    sort_order: int = 0


class TargetUpdate(BaseModel):
    name: str | None = Field(default=None, min_length=1, max_length=120)
    target_type: str | None = Field(default=None, max_length=32)
    latitude: float | None = None
    longitude: float | None = None
    x_percent: float | None = Field(default=None, ge=0, le=100)
    y_percent: float | None = Field(default=None, ge=0, le=100)
    canton: str | None = None
    difficulty: int | None = Field(default=None, ge=1, le=5)
    info_text: str | None = None
    active: bool | None = None
    sort_order: int | None = None


@router.get("/challenges/players")
def challenge_players(session: Session = Depends(get_session)) -> dict:
    return players(session)


@router.get("/challenges/geo/today")
def geo_today(player_id: int = Query(...), session: Session = Depends(get_session)) -> dict:
    return today_geo(session, player_id)


@router.post("/challenges/geo/attempt")
def geo_attempt(payload: GeoAttemptRequest, session: Session = Depends(get_session)) -> dict:
    return create_geo_attempt(session, payload.player_id, payload.target_id, payload.selected_x_percent, payload.selected_y_percent)


@router.get("/challenges/leaderboard")
def challenge_leaderboard(week_start: date | None = Query(default=None), session: Session = Depends(get_session)) -> dict:
    return leaderboard(session, week_start)


@router.get("/challenges/geo/summary")
def challenge_summary(player_id: int = Query(...), session: Session = Depends(get_session)) -> dict:
    return today_geo(session, player_id).get("summary", {})


@router.get("/admin/challenges/targets", dependencies=[Depends(require_admin)])
def admin_targets(session: Session = Depends(get_session)) -> dict:
    rows = session.exec(select(GeoChallengeTarget).order_by(GeoChallengeTarget.sort_order, GeoChallengeTarget.name)).all()
    return {"targets": [row.model_dump() for row in rows]}


@router.post("/admin/challenges/targets", status_code=201, dependencies=[Depends(require_admin)])
def admin_create_target(payload: TargetCreate, session: Session = Depends(get_session)) -> dict:
    target = GeoChallengeTarget(**payload.model_dump())
    session.add(target)
    session.commit()
    session.refresh(target)
    return {"target": target.model_dump()}


@router.patch("/admin/challenges/targets/{target_id}", dependencies=[Depends(require_admin)])
def admin_update_target(target_id: int, payload: TargetUpdate, session: Session = Depends(get_session)) -> dict:
    target = session.get(GeoChallengeTarget, target_id)
    if target is None:
        raise HTTPException(status_code=404, detail={"code": "target_not_found", "message": "Ziel nicht gefunden"})
    for key, value in payload.model_dump(exclude_unset=True).items():
        setattr(target, key, value)
    session.add(target)
    session.commit()
    session.refresh(target)
    return {"target": target.model_dump()}


@router.delete("/admin/challenges/targets/{target_id}", dependencies=[Depends(require_admin)])
def admin_delete_target(target_id: int, session: Session = Depends(get_session)) -> dict:
    target = session.get(GeoChallengeTarget, target_id)
    if target is None:
        raise HTTPException(status_code=404, detail={"code": "target_not_found", "message": "Ziel nicht gefunden"})
    target.active = False
    session.add(target)
    session.commit()
    session.refresh(target)
    return {"ok": True, "target": target.model_dump()}


@router.post("/admin/challenges/weekly-convert", dependencies=[Depends(require_admin)])
def admin_weekly_convert(session: Session = Depends(get_session)) -> dict:
    return weekly_convert(session)
