from __future__ import annotations

from datetime import datetime, timedelta

from fastapi import APIRouter, Depends, Query
import json
from pathlib import Path
from typing import Literal
from sqlalchemy import select, text
from sqlalchemy.orm import Session

from app.core.database import get_db
from app.core.dependencies import get_current_admin
from app.core.responses import api_success
from app.models.admin import Admin
from app.schemas.admin import DashboardStats
from app.services.admin_service import AdminDashboardService
from app.models.logs import StorageSnapshot
from app.services.redis_client import get_sync_redis_client
from app.services.request_traffic_service import RequestTrafficService

router = APIRouter()


@router.get("/dashboard")
def dashboard(
    start: str = Query(default="", description="开始日期 YYYY-MM-DD"),
    end: str = Query(default="", description="结束日期 YYYY-MM-DD"),
    db: Session = Depends(get_db),
    current_admin: Admin = Depends(get_current_admin),
) -> dict:
    start_dt = datetime.strptime(start, "%Y-%m-%d") if start else None
    if end:
        end_dt = datetime.strptime(end, "%Y-%m-%d")
        end_dt = end_dt.replace(hour=23, minute=59, second=59)
    else:
        end_dt = None
    stats = AdminDashboardService.stats(db, start_dt, end_dt)
    return api_success(DashboardStats.model_validate(stats).model_dump())


@router.get("/dashboard/traffic")
async def peak_traffic(
    grain: Literal["minute", "hour", "day", "week"] = Query(default="hour"),
    current_admin: Admin = Depends(get_current_admin),
) -> dict:
    return api_success(await RequestTrafficService.peak_traffic(grain))


@router.get("/dashboard/storage")
def storage_stats(
    refresh: bool = Query(default=False),
    db: Session = Depends(get_db),
    current_admin: Admin = Depends(get_current_admin),
) -> dict:
    latest = db.scalar(select(StorageSnapshot).where(StorageSnapshot.scope == "project").order_by(StorageSnapshot.id.desc()).limit(1))
    if latest is not None and not refresh:
        return api_success(_snapshot_dict(latest, db))
    detail: dict = {"database": {"status": "unavailable", "bytes": None, "tables": []}, "redis": {"status": "unavailable", "bytes": None}, "files": {"status": "unavailable", "bytes": None}}
    errors: list[str] = []
    try:
        if db.bind and db.bind.dialect.name == "mysql":
            rows = db.execute(text("SELECT table_name, data_length + index_length AS bytes FROM information_schema.tables WHERE table_schema = DATABASE() ORDER BY bytes DESC")).all()
            tables = [{"name": row[0], "bytes": int(row[1] or 0)} for row in rows]
            detail["database"] = {"status": "ok", "bytes": sum(x["bytes"] for x in tables), "tables": tables}
        else:
            detail["database"] = {"status": "unavailable", "bytes": None, "tables": [], "message": "当前数据库不支持精确表占用统计"}
    except Exception as exc:
        errors.append(f"database: {exc}")
    try:
        redis = get_sync_redis_client()
        if redis is not None:
            info = redis.info("memory")
            detail["redis"] = {"status": "ok", "bytes": int(info.get("used_memory", 0))}
    except Exception as exc:
        errors.append(f"redis: {exc}")
    try:
        root = Path(".uploads")
        if root.exists():
            detail["files"] = {"status": "ok", "bytes": sum(p.stat().st_size for p in root.rglob("*") if p.is_file())}
        else:
            detail["files"] = {"status": "unavailable", "bytes": None, "message": "项目未配置本地附件目录"}
    except Exception as exc:
        errors.append(f"files: {exc}")
    known = [x.get("bytes") for x in detail.values() if x.get("status") == "ok"]
    snapshot = StorageSnapshot(scope="project", total_bytes=sum(known) if known else None, detail_json=json.dumps(detail, ensure_ascii=False), status="partial" if errors or any(x.get("status") != "ok" for x in detail.values()) else "ok", error_message="; ".join(errors) or None)
    db.add(snapshot); db.commit(); db.refresh(snapshot)
    return api_success(_snapshot_dict(snapshot, db))


def _snapshot_dict(item: StorageSnapshot, db: Session) -> dict:
    with_growth = {"totalBytes": item.total_bytes, "detail": json.loads(item.detail_json), "status": item.status, "errorMessage": item.error_message, "createdAt": item.created_at}
    # Growth is intentionally unknown until enough snapshots exist; never report a misleading zero.
    for days, key in ((7, "growth7DaysBytes"), (30, "growth30DaysBytes")):
        previous = db.scalar(select(StorageSnapshot).where(StorageSnapshot.scope == item.scope, StorageSnapshot.created_at <= item.created_at - timedelta(days=days)).order_by(StorageSnapshot.created_at.desc()).limit(1))
        with_growth[key] = item.total_bytes - previous.total_bytes if previous and item.total_bytes is not None and previous.total_bytes is not None else None
    return with_growth
