"""Garment analysis, management, and listing endpoints."""

import uuid

from fastapi import APIRouter, Depends, File, Form, HTTPException, Query, UploadFile
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import joinedload

from app.config import GLOBAL_USER_ID
from app.dependencies import get_db, get_face_service, get_garment_service, get_wardrobe_service
from app.models.garment import Garment
from app.models.user import User
from app.schemas.common import GarmentBrief, ImageModel, PageMeta
from app.schemas.garment import (
    FaceStatus,
    GarmentAnalysisItem,
    GarmentAnalyzeResponse,
    GarmentBulkUpdateRequest,
    GarmentBulkUpdateResponse,
    GarmentDeleteResponse,
    GarmentDetail,
    GarmentListResponse,
    GarmentSaveRequest,
    GarmentSaveResponse,
    GarmentUpdateRequest,
    GarmentUpdateResponse,
    GhostGenerateResponse,
    GhostPreviewRequest,
    GhostPreviewResponse,
    StyleAnalyzeResponse,
    StyleAnalyzeTempResponse,
)
from app.services.face_service import FaceService
from app.services.garment_service import GarmentService
from app.services.wardrobe_service import WardrobeService

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


def _garment_to_analysis_item(g: Garment) -> GarmentAnalysisItem:
    source_url = f"/storage/{g.source_image_path}" if g.source_image_path else None
    ghost_url = f"/storage/{g.ghost_image_path}" if g.ghost_image_path else None
    return GarmentAnalysisItem(
        id=g.id,
        category_main=g.category_main,
        category_sub=g.category_sub,
        description=g.description,
        tags=g.tags,
        source_image_url=source_url,
        ghost_image_url=ghost_url,
    )


# ---------------------------------------------------------------------------
# Analyze (unified: optional face identification)
# ---------------------------------------------------------------------------


@router.post("/analyze", response_model=GarmentAnalyzeResponse)
async def analyze_garment(
    image: UploadFile = File(...),
    user_id: uuid.UUID | None = Form(None),
    use_face_id: bool = Form(False),
    auto_save: bool = Form(True),
    db: AsyncSession = Depends(get_db),
    garment_svc: GarmentService = Depends(get_garment_service),
    face_svc: FaceService = Depends(get_face_service),
):
    """Analyze garment from image.

    Args:
        auto_save: If True (default), save garments to DB immediately.
            If False, return analysis results only — use POST /save to persist later.

    Priority:
    - user_id provided → use it directly (face_status=skipped)
    - use_face_id=true → attempt face identification
    - neither → global user (face_status=skipped)
    """
    image_bytes = await image.read()

    resolved_user_id = GLOBAL_USER_ID
    user_name: str | None = "unknown"
    face_status = FaceStatus.not_used

    if user_id is not None:
        # Explicit user_id — skip face detection
        resolved_user_id = user_id
        face_status = FaceStatus.not_used
        # Look up user name
        user_result = await db.execute(select(User).where(User.id == user_id))
        user = user_result.scalar_one_or_none()
        user_name = user.name if user else None
    elif use_face_id:
        try:
            result = await face_svc.identify(db, image_bytes)
            if result is not None:
                resolved_user_id = result["user_id"]
                user_name = result["user_name"]
                face_status = FaceStatus.known
            else:
                # Face detected but not registered
                face_status = FaceStatus.unknown
        except ValueError:
            # No face detected in image
            face_status = FaceStatus.not_detected

    if auto_save:
        # Original behavior: analyze + save to DB
        try:
            garments = await garment_svc.analyze_and_save(db, image_bytes, resolved_user_id)
        except Exception as e:
            raise HTTPException(status_code=500, detail=f"분석 실패: {e}")

        return GarmentAnalyzeResponse(
            user_id=resolved_user_id,
            user_name=user_name,
            face_status=face_status,
            saved=True,
            garments=[_garment_to_analysis_item(g) for g in garments],
        )
    else:
        # Analyze only — no DB save
        try:
            items, source_path = await garment_svc.analyze_only(image_bytes, resolved_user_id)
        except Exception as e:
            raise HTTPException(status_code=500, detail=f"분석 실패: {e}")

        source_url = f"/storage/{source_path}" if source_path else None
        analysis_items = [
            GarmentAnalysisItem(
                id=None,
                category_main=item.category_main,
                category_sub=item.category_sub,
                description=item.description,
                tags=item.tags,
                source_image_url=source_url,
                ghost_image_url=None,
            )
            for item in items
        ]

        return GarmentAnalyzeResponse(
            user_id=resolved_user_id,
            user_name=user_name,
            face_status=face_status,
            saved=False,
            source_image_path=source_path,
            garments=analysis_items,
        )


# ---------------------------------------------------------------------------
# Style analysis (overall outfit evaluation)
# ---------------------------------------------------------------------------


@router.post("/style-analyze", response_model=StyleAnalyzeResponse)
async def style_analyze(
    image: UploadFile = File(...),
    garment_svc: GarmentService = Depends(get_garment_service),
):
    """Analyze overall outfit style from image.

    Returns scores (1-5) for color palette, silhouette, and detail,
    plus an overall score, comment, and style tags.
    """
    image_bytes = await image.read()

    try:
        result = await garment_svc.analyze_style(image_bytes)
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"스타일 분석 실패: {e}")

    return StyleAnalyzeResponse(**result.model_dump())


@router.post("/style-analyze-temp", response_model=StyleAnalyzeTempResponse)
async def style_analyze_temp(
    image: UploadFile = File(...),
    garment_svc: GarmentService = Depends(get_garment_service),
):
    """Context-aware outfit style analysis (time/occasion/weather).

    Returns 5 contextual sections instead of scores.
    """
    image_bytes = await image.read()

    try:
        result = await garment_svc.analyze_style_temp(image_bytes)
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"스타일 분석 실패: {e}")

    return StyleAnalyzeTempResponse(**result.model_dump())


# ---------------------------------------------------------------------------
# Save analyzed garments to DB (after analyze with auto_save=false)
# ---------------------------------------------------------------------------


@router.post("/save", response_model=GarmentSaveResponse)
async def save_garments(
    body: GarmentSaveRequest,
    db: AsyncSession = Depends(get_db),
    garment_svc: GarmentService = Depends(get_garment_service),
):
    """Save analyzed garments to DB.

    Use after POST /analyze with auto_save=false.
    Client can selectively choose which garments to persist.
    """
    from app.services.llm.base import GarmentAnalysis

    items = [
        GarmentAnalysis(
            category_main=g.category_main,
            category_sub=g.category_sub,
            description=g.description,
            tags=g.tags,
        )
        for g in body.garments
    ]

    ghost_paths = [g.ghost_image_path for g in body.garments]

    try:
        garments = await garment_svc.save_garments(
            db, items, body.source_image_path, body.user_id, ghost_paths
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"저장 실패: {e}")

    resolved_user_id = body.user_id or GLOBAL_USER_ID
    return GarmentSaveResponse(
        user_id=resolved_user_id,
        garments=[_garment_to_analysis_item(g) for g in garments],
    )


# ---------------------------------------------------------------------------
# Ghost mannequin preview (stateless, before save)
# ---------------------------------------------------------------------------


@router.post("/ghost-preview", response_model=GhostPreviewResponse)
async def ghost_preview(
    body: GhostPreviewRequest,
    garment_svc: GarmentService = Depends(get_garment_service),
):
    """Generate ghost mannequin preview without saving to DB.

    Use after POST /analyze with auto_save=false, before POST /save.
    Returns ghost image URL and path (pass path to /save).
    """
    from app.services.llm.base import GarmentAnalysis

    item = GarmentAnalysis(
        category_main=body.category_main,
        category_sub=body.category_sub,
        description=body.description,
        tags=body.tags,
    )

    try:
        ghost_path = await garment_svc.generate_ghost_preview(
            body.source_image_path,
            item,
            body.user_id,
            body.image_model.value if body.image_model else None,
        )
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e))
    except RuntimeError as e:
        raise HTTPException(status_code=502, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"마네킹 프리뷰 실패: {e}")

    ghost_url = f"/storage/{ghost_path}"
    return GhostPreviewResponse(ghost_image_url=ghost_url, ghost_image_path=ghost_path)


# ---------------------------------------------------------------------------
# Ghost mannequin generation (slow, separate step)
# ---------------------------------------------------------------------------


@router.post("/{garment_id}/ghost", response_model=GhostGenerateResponse)
async def generate_ghost(
    garment_id: uuid.UUID,
    image_model: ImageModel | None = Query(
        None,
        description="이미지 생성 모델 (gpt-image-2 / gpt-image-1.5). 미지정 시 서버 기본값.",
    ),
    db: AsyncSession = Depends(get_db),
    garment_svc: GarmentService = Depends(get_garment_service),
):
    """Generate ghost mannequin image for a garment (slow operation)."""
    try:
        garment = await garment_svc.generate_ghost(
            db, garment_id, image_model.value if image_model else None
        )
    except ValueError as e:
        # Garment not found / source image missing
        raise HTTPException(status_code=404, detail=str(e))
    except RuntimeError as e:
        # LLM generation failure (external API error)
        raise HTTPException(status_code=502, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"마네킹 생성 실패: {e}")

    ghost_url = f"/storage/{garment.ghost_image_path}" if garment.ghost_image_path else ""
    return GhostGenerateResponse(id=garment.id, ghost_image_url=ghost_url)


# ---------------------------------------------------------------------------
# Listing (replaces /wardrobe/{user_id})
# ---------------------------------------------------------------------------


@router.get("", response_model=GarmentListResponse)
async def list_garments(
    user_id: uuid.UUID | None = Query(None, description="유저 필터 (없으면 전체)"),
    category_main: str | None = Query(None, description="대분류 필터 (top, bottom, outer, ...)"),
    category_sub: str | None = Query(None, description="소분류 필터 (t-shirt, jeans, ...)"),
    style: str | None = Query(None, description="스타일 필터 (casual, formal, sporty, streetwear)"),
    color: str | None = Query(None, description="색상 필터 (black, white, ...)"),
    page: int = Query(1, ge=1),
    size: int = Query(20, ge=1, le=100),
    db: AsyncSession = Depends(get_db),
    wardrobe_svc: WardrobeService = Depends(get_wardrobe_service),
):
    """List garments with optional filters. user_id=null → all users."""
    garments, total = await wardrobe_svc.list_garments(
        db,
        user_id=user_id,
        category_main=category_main,
        category_sub=category_sub,
        style=style,
        color=color,
        page=page,
        size=size,
    )

    items = [
        GarmentBrief(
            id=g.id,
            user_id=g.user_id,
            user_name=g.user.name if g.user else None,
            category_main=g.category_main,
            category_sub=g.category_sub,
            description=g.description,
            tags=g.tags,
            source_image_path=g.source_image_path,
            source_image_url=f"/storage/{g.source_image_path}" if g.source_image_path else None,
            ghost_image_path=g.ghost_image_path,
            ghost_image_url=f"/storage/{g.ghost_image_path}" if g.ghost_image_path else None,
            created_at=g.created_at,
        )
        for g in garments
    ]

    return GarmentListResponse(
        items=items,
        meta=PageMeta(page=page, size=size, total=total),
    )


# ---------------------------------------------------------------------------
# Single garment detail
# ---------------------------------------------------------------------------


@router.get("/{garment_id}", response_model=GarmentDetail)
async def get_garment(
    garment_id: uuid.UUID,
    db: AsyncSession = Depends(get_db),
):
    """Get single garment detail."""
    result = await db.execute(
        select(Garment).options(joinedload(Garment.user)).where(Garment.id == garment_id)
    )
    garment = result.unique().scalar_one_or_none()
    if garment is None:
        raise HTTPException(status_code=404, detail="아이템을 찾을 수 없습니다.")
    return GarmentDetail(
        id=garment.id,
        user_id=garment.user_id,
        user_name=garment.user.name if garment.user else None,
        category_main=garment.category_main,
        category_sub=garment.category_sub,
        description=garment.description,
        tags=garment.tags,
        source_image_path=garment.source_image_path,
        source_image_url=f"/storage/{garment.source_image_path}" if garment.source_image_path else None,
        ghost_image_path=garment.ghost_image_path,
        ghost_image_url=f"/storage/{garment.ghost_image_path}" if garment.ghost_image_path else None,
        created_at=garment.created_at,
        updated_at=garment.updated_at,
    )


# ---------------------------------------------------------------------------
# Bulk update (reassign multiple garments) — must be before /{garment_id}
# ---------------------------------------------------------------------------


@router.patch("/bulk", response_model=GarmentBulkUpdateResponse)
async def bulk_update_garments(
    body: GarmentBulkUpdateRequest,
    db: AsyncSession = Depends(get_db),
):
    """Reassign multiple garments to a different user."""
    # Verify target user exists
    user_result = await db.execute(select(User).where(User.id == body.user_id))
    target_user = user_result.scalar_one_or_none()
    if target_user is None:
        raise HTTPException(status_code=404, detail="대상 사용자를 찾을 수 없습니다.")

    result = await db.execute(
        select(Garment).where(Garment.id.in_(body.garment_ids))
    )
    garments = list(result.scalars().all())

    for g in garments:
        g.user_id = body.user_id

    await db.commit()

    return GarmentBulkUpdateResponse(
        updated_count=len(garments),
        user_id=target_user.id,
        user_name=target_user.name,
    )


# ---------------------------------------------------------------------------
# Update (reassign to different user)
# ---------------------------------------------------------------------------


@router.patch("/{garment_id}", response_model=GarmentUpdateResponse)
async def update_garment(
    garment_id: uuid.UUID,
    body: GarmentUpdateRequest,
    db: AsyncSession = Depends(get_db),
):
    """Update garment ownership (reassign to a different user)."""
    result = await db.execute(select(Garment).where(Garment.id == garment_id))
    garment = result.scalar_one_or_none()
    if garment is None:
        raise HTTPException(status_code=404, detail="아이템을 찾을 수 없습니다.")

    # Verify target user exists
    user_result = await db.execute(select(User).where(User.id == body.user_id))
    target_user = user_result.scalar_one_or_none()
    if target_user is None:
        raise HTTPException(status_code=404, detail="대상 사용자를 찾을 수 없습니다.")

    garment.user_id = body.user_id
    await db.commit()

    return GarmentUpdateResponse(
        id=garment.id,
        user_id=target_user.id,
        user_name=target_user.name,
    )


# ---------------------------------------------------------------------------
# Delete
# ---------------------------------------------------------------------------


@router.delete("/{garment_id}", response_model=GarmentDeleteResponse)
async def delete_garment(
    garment_id: uuid.UUID,
    db: AsyncSession = Depends(get_db),
):
    """Delete a garment."""
    result = await db.execute(select(Garment).where(Garment.id == garment_id))
    garment = result.scalar_one_or_none()
    if garment is None:
        raise HTTPException(status_code=404, detail="아이템을 찾을 수 없습니다.")

    from app.utils.image import delete_image

    source_path = garment.source_image_path
    ghost_path = garment.ghost_image_path

    await db.delete(garment)
    await db.commit()

    delete_image(source_path)
    delete_image(ghost_path)

    return GarmentDeleteResponse(id=garment_id)
