"""Admin endpoints for data management and cleanup."""

import logging
from pathlib import Path
from typing import Literal

from fastapi import APIRouter, Depends
from pydantic import BaseModel
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.config import settings
from app.dependencies import get_db, get_garment_service
from app.models.face import FaceEmbedding
from app.models.garment import Garment
from app.services.garment_service import GarmentService
from app.services.seed_service import (
    ResetSummary,
    SeedSummary,
    reset_all_data,
    seed_wardrobe,
)

logger = logging.getLogger(__name__)

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


# ---------------------------------------------------------------------------
# Schemas
# ---------------------------------------------------------------------------


class OrphanCleanupResponse(BaseModel):
    orphaned_files: list[str]
    deleted_count: int


class SeedRequest(BaseModel):
    mode: Literal["reset", "add"] = "add"
    resource_dirs: list[str] | None = None


# ---------------------------------------------------------------------------
# Full reset
# ---------------------------------------------------------------------------


@router.delete("/reset", response_model=ResetSummary)
async def reset_all(
    db: AsyncSession = Depends(get_db),
):
    """Delete ALL data (garments, faces, non-global users) and clear storage.

    The global user is preserved but its garments are deleted.
    """
    return await reset_all_data(db)


# ---------------------------------------------------------------------------
# Seed preset wardrobe
# ---------------------------------------------------------------------------


@router.post("/seed", response_model=SeedSummary)
async def seed(
    req: SeedRequest,
    db: AsyncSession = Depends(get_db),
    garment_service: GarmentService = Depends(get_garment_service),
):
    """Populate the unknown user's wardrobe from preset garment images.

    Blocking for minutes (17 images × analyze + ghost LLM calls). For POC use.
    Set mode="reset" to wipe existing data first.
    """
    dirs = [Path(d) for d in req.resource_dirs] if req.resource_dirs else None
    return await seed_wardrobe(db, garment_service, mode=req.mode, resource_dirs=dirs)


# ---------------------------------------------------------------------------
# Orphan file cleanup
# ---------------------------------------------------------------------------


@router.post("/cleanup", response_model=OrphanCleanupResponse)
async def cleanup_orphans(
    dry_run: bool = True,
    db: AsyncSession = Depends(get_db),
):
    """Find and optionally delete orphaned files not referenced in DB.

    - dry_run=true (default): list orphaned files without deleting
    - dry_run=false: actually delete orphaned files
    """
    # Collect all image paths referenced in DB
    garment_result = await db.execute(select(Garment))
    garments = garment_result.scalars().all()
    face_result = await db.execute(select(FaceEmbedding))
    faces = face_result.scalars().all()

    db_paths: set[str] = set()
    for g in garments:
        if g.source_image_path:
            db_paths.add(g.source_image_path)
        if g.ghost_image_path:
            db_paths.add(g.ghost_image_path)
    for f in faces:
        if f.image_path:
            db_paths.add(f.image_path)

    # Scan storage for actual files
    base = Path(settings.UPLOAD_DIR)
    orphaned: list[str] = []
    for sub in ("originals", "ghost_mannequin", "faces", "segmentation"):
        sub_dir = base / sub
        if not sub_dir.is_dir():
            continue
        for filepath in sub_dir.rglob("*"):
            if not filepath.is_file():
                continue
            rel = str(filepath.relative_to(base))
            if rel not in db_paths:
                orphaned.append(rel)

    deleted_count = 0
    if not dry_run:
        for rel in orphaned:
            full_path = base / rel
            try:
                full_path.unlink()
                deleted_count += 1
                logger.info("Deleted orphan: %s", rel)
            except OSError:
                logger.warning("Failed to delete orphan: %s", rel, exc_info=True)

        # Clean up empty directories
        for sub in ("originals", "ghost_mannequin", "faces", "segmentation"):
            sub_dir = base / sub
            if not sub_dir.is_dir():
                continue
            for d in sorted(sub_dir.rglob("*"), reverse=True):
                if d.is_dir() and not any(d.iterdir()):
                    d.rmdir()

    return OrphanCleanupResponse(
        orphaned_files=orphaned,
        deleted_count=deleted_count,
    )
