from __future__ import annotations

import os
from datetime import datetime, timezone
from pathlib import Path
from typing import Any

from fastapi import APIRouter, Depends, HTTPException, Request
from pydantic import BaseModel, Field

from app.auth import (
    ADMIN_USERNAME,
    admin_configured,
    check_login_rate_limit,
    create_access_token,
    record_failed_login,
    require_admin,
    verify_password,
)
from app.cache import cache_get, cache_set, redis_available
from app.config import (
    APP_NAME,
    APP_VERSION,
    BRIGHTSKY_BASE_URL,
    CACHE_TTL_FORECAST,
    CACHE_TTL_GEOCODE,
    CACHE_TTL_OBSERVATIONS,
    CACHE_TTL_WARNINGS,
    CACHE_TTL_WMS_TIMES,
    DATA_DIR,
    DWD_RADAR_BASE_URL,
    DWD_WMS_URL,
    OPEN_METEO_BASE_URL,
    RADAR_PRODUCT,
    RADAR_RETENTION_HOURS,
    RATE_LIMIT_PER_MINUTE,
    RAW_RADAR_DIR,
    RENDERED_RADAR_DIR,
)
from app.database import pool_available
from app.services.health import check_sources

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


class LoginRequest(BaseModel):
    username: str = Field(min_length=1, max_length=64)
    password: str = Field(min_length=8, max_length=128)


class SettingsUpdate(BaseModel):
    rate_limit_per_minute: int | None = Field(default=None, ge=10, le=1000)
    cache_ttl_forecast: int | None = Field(default=None, ge=60, le=86400)
    cache_ttl_observations: int | None = Field(default=None, ge=60, le=86400)
    cache_ttl_warnings: int | None = Field(default=None, ge=30, le=3600)
    radar_retention_hours: int | None = Field(default=None, ge=6, le=168)


def _dir_stats(path: Path) -> dict[str, Any]:
    if not path.exists():
        return {"path": str(path), "exists": False, "files": 0, "bytes": 0}
    files = [p for p in path.rglob("*") if p.is_file()]
    total = sum(p.stat().st_size for p in files)
    return {"path": str(path), "exists": True, "files": len(files), "bytes": total}


def _public_config() -> dict[str, Any]:
    return {
        "app_name": APP_NAME,
        "version": APP_VERSION,
        "open_meteo_base_url": OPEN_METEO_BASE_URL,
        "brightsky_base_url": BRIGHTSKY_BASE_URL,
        "dwd_radar_base_url": DWD_RADAR_BASE_URL,
        "dwd_wms_url": DWD_WMS_URL,
        "radar_product": RADAR_PRODUCT,
        "radar_retention_hours": RADAR_RETENTION_HOURS,
        "rate_limit_per_minute": RATE_LIMIT_PER_MINUTE,
        "cache_ttl": {
            "forecast": CACHE_TTL_FORECAST,
            "observations": CACHE_TTL_OBSERVATIONS,
            "warnings": CACHE_TTL_WARNINGS,
            "geocode": CACHE_TTL_GEOCODE,
            "wms_times": CACHE_TTL_WMS_TIMES,
        },
    }


@router.get("/status")
async def admin_status_public() -> dict[str, Any]:
    return {"admin_enabled": admin_configured(), "version": APP_VERSION}


@router.post("/login")
async def admin_login(request: Request, payload: LoginRequest) -> dict[str, Any]:
    if not admin_configured():
        raise HTTPException(status_code=503, detail="Admin login is not configured on this instance")
    check_login_rate_limit(request)
    if payload.username != ADMIN_USERNAME or not verify_password(payload.password, os.getenv("ADMIN_PASSWORD_HASH", "")):
        record_failed_login(request)
        raise HTTPException(status_code=401, detail="Invalid credentials")
    token = create_access_token(payload.username)
    return {
        "access_token": token,
        "token_type": "bearer",
        "expires_in_hours": int(os.getenv("ADMIN_JWT_EXPIRE_HOURS", "8")),
    }


@router.get("/dashboard")
async def admin_dashboard(_: dict[str, Any] = Depends(require_admin)) -> dict[str, Any]:
    sources = await check_sources()
    return {
        "time_utc": datetime.now(timezone.utc).isoformat(),
        "services": sources,
        "infrastructure": {
            "postgres": "ok" if pool_available() else "disabled",
            "redis": "ok" if redis_available() else "disabled",
        },
        "storage": {
            "data_dir": _dir_stats(DATA_DIR),
            "radar_raw": _dir_stats(RAW_RADAR_DIR),
            "radar_rendered": _dir_stats(RENDERED_RADAR_DIR),
        },
        "config": _public_config(),
    }


@router.post("/cache/clear")
async def admin_clear_cache(_: dict[str, Any] = Depends(require_admin)) -> dict[str, Any]:
    from app.cache import flush_cache

    if not redis_available():
        raise HTTPException(status_code=503, detail="Redis cache is not available")
    await flush_cache()
    return {"status": "ok", "message": "Redis cache cleared"}


@router.get("/settings")
async def admin_get_settings(_: dict[str, Any] = Depends(require_admin)) -> dict[str, Any]:
    runtime = await cache_get("admin:runtime_settings") or {}
    return {"defaults": _public_config(), "runtime_overrides": runtime}


@router.put("/settings")
async def admin_update_settings(payload: SettingsUpdate, _: dict[str, Any] = Depends(require_admin)) -> dict[str, Any]:
    from app.cache import cache_set

    current = await cache_get("admin:runtime_settings") or {}
    updates = payload.model_dump(exclude_none=True)
    if not updates:
        raise HTTPException(status_code=400, detail="No settings provided")
    current.update(updates)
    await cache_set("admin:runtime_settings", current, ttl_seconds=86400 * 30)
    return {"status": "ok", "runtime_overrides": current, "note": "Overrides are stored in Redis. Service restart applies full .env changes."}
