from datetime import date

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

from app.db.session import get_session
from app.services.admin_auth import get_admin_session
from app.services.screen_time import (
    admin_screen_time_range,
    create_earn_rule,
    earn_screen_time,
    exchange_coins_for_screen_time,
    list_earn_rules,
    list_screen_time,
    start_screen_time,
    stop_screen_time,
    undo_earned_screen_time,
    update_day_allowance,
    update_earn_rule,
    weekly_report,
)

router = APIRouter(tags=["screen-time"])


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 ScreenTimeActionRequest(BaseModel):
    date: date
    idempotency_key: str | None = None


class ScreenTimeExchangeRequest(BaseModel):
    child_id: int
    date: date
    idempotency_key: str | None = None


class ScreenTimeAllowanceUpdate(BaseModel):
    base_minutes: int | None = Field(default=None, ge=0)
    bonus_minutes: int | None = Field(default=None, ge=0)
    adjustment_minutes: int | None = None
    locked: bool | None = None
    notes: str | None = Field(default=None, max_length=240)


class ScreenTimeEarnRequest(BaseModel):
    child_id: int
    rule_id: int
    date: date
    idempotency_key: str | None = None


class EarnRuleCreate(BaseModel):
    slug: str = Field(min_length=1, max_length=120)
    title: str = Field(min_length=1, max_length=160)
    description: str = ""
    required_minutes: int = Field(default=20, ge=1)
    reward_minutes: int = Field(default=10, ge=1)
    coin_reward: int = Field(default=1, ge=0)
    child_id: int | None = None
    active: bool = True
    sort_order: int = 0


class EarnRuleUpdate(BaseModel):
    slug: str | None = Field(default=None, min_length=1, max_length=120)
    title: str | None = Field(default=None, min_length=1, max_length=160)
    description: str | None = None
    required_minutes: int | None = Field(default=None, ge=1)
    reward_minutes: int | None = Field(default=None, ge=1)
    coin_reward: int | None = Field(default=None, ge=0)
    child_id: int | None = None
    active: bool | None = None
    sort_order: int | None = None


@router.get("/screen-time")
def get_screen_time(date: date, session: Session = Depends(get_session)) -> dict:
    return list_screen_time(session, date)


@router.post("/screen-time/{child_id}/start")
def post_start_screen_time(child_id: int, payload: ScreenTimeActionRequest, session: Session = Depends(get_session)) -> dict:
    return start_screen_time(session, child_id, payload.date, payload.idempotency_key)


@router.post("/screen-time/{child_id}/stop")
def post_stop_screen_time(child_id: int, payload: ScreenTimeActionRequest, session: Session = Depends(get_session)) -> dict:
    return stop_screen_time(session, child_id, payload.date)


@router.post("/screen-time/exchange")
def post_screen_time_exchange(payload: ScreenTimeExchangeRequest, session: Session = Depends(get_session)) -> dict:
    return exchange_coins_for_screen_time(session, payload.child_id, payload.date, payload.idempotency_key)


@router.get("/admin/screen-time", dependencies=[Depends(require_admin)])
def get_admin_screen_time(start: date, days: int = 7, session: Session = Depends(get_session)) -> dict:
    return admin_screen_time_range(session, start, days)


@router.post("/screen-time/earn")
def post_screen_time_earn(payload: ScreenTimeEarnRequest, session: Session = Depends(get_session)) -> dict:
    return earn_screen_time(session, payload.child_id, payload.rule_id, payload.date, payload.idempotency_key)


@router.post("/screen-time/earn/undo")
def post_screen_time_earn_undo(payload: ScreenTimeEarnRequest, session: Session = Depends(get_session)) -> dict:
    return undo_earned_screen_time(session, payload.child_id, payload.rule_id, payload.date)


@router.get("/admin/screen-time/report", dependencies=[Depends(require_admin)])
def get_admin_screen_time_report(start: date, days: int = 7, session: Session = Depends(get_session)) -> dict:
    return weekly_report(session, start, days)


@router.get("/admin/screen-time/earn-rules", dependencies=[Depends(require_admin)])
def get_admin_earn_rules(session: Session = Depends(get_session)) -> dict:
    return list_earn_rules(session)


@router.post("/admin/screen-time/earn-rules", status_code=201, dependencies=[Depends(require_admin)])
def post_admin_earn_rule(payload: EarnRuleCreate, session: Session = Depends(get_session)) -> dict:
    return create_earn_rule(session, payload.model_dump())


@router.patch("/admin/screen-time/earn-rules/{rule_id}", dependencies=[Depends(require_admin)])
def patch_admin_earn_rule(rule_id: int, payload: EarnRuleUpdate, session: Session = Depends(get_session)) -> dict:
    return update_earn_rule(session, rule_id, payload.model_dump(exclude_unset=True))


@router.patch("/admin/screen-time/{child_id}/{target_date}", dependencies=[Depends(require_admin)])
def patch_admin_screen_time(child_id: int, target_date: date, payload: ScreenTimeAllowanceUpdate, session: Session = Depends(get_session)) -> dict:
    return update_day_allowance(session, child_id, target_date, payload.model_dump(exclude_unset=True))
