from datetime import date

from fastapi import APIRouter, Depends
from pydantic import BaseModel

from advent22_api.core.helpers import EventDates

from ..core.calendar_config import (
    CalendarConfig,
    DoorsSaved,
    get_calendar_config,
)
from ..core.config import Config, Image, get_config
from ..core.depends import (
    TTFont,
    get_all_event_dates,
    get_all_image_names,
    get_all_parts,
    get_all_ttfonts,
)
from ..core.settings import SETTINGS, Credentials, RedisSettings
from ._security import require_admin, user_is_admin

router = APIRouter(prefix="/admin", tags=["admin"])


@router.get("/is_admin")
async def is_admin(
    is_admin: bool = Depends(user_is_admin),
) -> bool:
    return is_admin


class AdminConfigModel(BaseModel):
    class __Solution(BaseModel):
        value: str
        whitespace: str
        special_chars: str
        case: str
        clean: str

    class __Puzzle(BaseModel):
        first: date
        next: date | None
        last: date
        end: date
        seed: str
        extra_days: list[int]
        skip_empty: bool

    class __Calendar(BaseModel):
        config_file: str
        background: str
        favicon: str

    class __Font(BaseModel):
        file: str
        size: int

    class __WebDAV(BaseModel):
        url: str
        cache_ttl: int
        config_file: str

    solution: __Solution
    puzzle: __Puzzle
    calendar: __Calendar
    image: Image
    fonts: list[__Font]
    redis: RedisSettings
    webdav: __WebDAV


@router.get("/config_model")
async def get_config_model(
    _: None = Depends(require_admin),
    cfg: Config = Depends(get_config),
    cal_cfg: CalendarConfig = Depends(get_calendar_config),
    event_dates: EventDates = Depends(get_all_event_dates),
    ttfonts: list[TTFont] = Depends(get_all_ttfonts),
) -> AdminConfigModel:
    """
    Kombiniert aus privaten `settings`, `config` und `calendar_config`
    """

    return AdminConfigModel.model_validate(
        {
            "solution": {
                "value": cfg.solution.value,
                "whitespace": cfg.solution.whitespace,
                "special_chars": cfg.solution.special_chars,
                "case": cfg.solution.case,
                "clean": cfg.solution.clean,
            },
            "puzzle": {
                "first": event_dates.first,
                "next": event_dates.next,
                "last": event_dates.last,
                "end": event_dates.end,
                "seed": cfg.random_seed,
                "extra_days": sorted(cfg.puzzle.extra_days),
                "skip_empty": cfg.puzzle.skip_empty,
            },
            "calendar": {
                "config_file": cfg.calendar,
                "background": cal_cfg.background,
                "favicon": cal_cfg.favicon,
            },
            "image": cfg.image,
            "fonts": [
                {"file": ttfont.file_name, "size": ttfont.size} for ttfont in ttfonts
            ],
            "redis": SETTINGS.redis,
            "webdav": {
                "url": SETTINGS.webdav.url,
                "cache_ttl": SETTINGS.webdav.cache_ttl,
                "config_file": SETTINGS.webdav.config_filename,
            },
        }
    )


@router.get("/day_image_names")
async def get_day_image_names(
    _: None = Depends(require_admin),
    image_names: dict[int, str] = Depends(get_all_image_names),
) -> dict[int, str]:
    """
    Zuordnung der verwendeten Bilder zu den Tagen
    """

    return image_names


@router.get("/day_parts")
async def get_day_parts(
    _: None = Depends(require_admin),
    parts: dict[int, str] = Depends(get_all_parts),
) -> dict[int, str]:
    """
    Zuordnung der Lösungsteile zu den Tagen
    """

    return parts


@router.get("/doors")
async def get_doors(
    _: None = Depends(require_admin),
    cal_cfg: CalendarConfig = Depends(get_calendar_config),
) -> DoorsSaved:
    """
    Türchen lesen
    """

    return cal_cfg.doors


@router.put("/doors")
async def put_doors(
    doors: DoorsSaved,
    _: None = Depends(require_admin),
    cfg: Config = Depends(get_config),
    cal_cfg: CalendarConfig = Depends(get_calendar_config),
) -> None:
    """
    Türchen ändern
    """

    cal_cfg.doors = sorted(
        doors,
        key=lambda door: door.day,
    )
    await cal_cfg.change(cfg)


@router.get("/credentials/{name}")
async def get_credentials(
    name: str,
    _: None = Depends(require_admin),
    cfg: Config = Depends(get_config),
) -> Credentials:

    if name == "dav":
        return SETTINGS.webdav.auth
    elif name == "ui":
        return cfg.admin
    else:
        return Credentials()
