from datetime import datetime, timezone
from uuid import UUID

from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload

from app.auth.demo_auth import get_admin_user
from app.database import get_db
from app.models.activity import Activity, ActivityCompletion
from app.models.anti_cheat import AnomalyFlag, VerificationRequest
from app.models.user import User

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


# --- Request models ---

class ResolveAnomalyRequest(BaseModel):
    approve: bool
    note: str | None = None


class ReviewVerificationRequest(BaseModel):
    approve: bool
    note: str | None = None


# --- Anomaly Flags ---

@router.get("/anomalies")
async def list_anomalies(
    resolved: bool | None = Query(None, description="Filter by resolved status"),
    severity: str | None = Query(None, description="Filter by severity: info, warning, critical"),
    limit: int = Query(50, le=200),
    offset: int = Query(0, ge=0),
    db: AsyncSession = Depends(get_db),
    admin: User = Depends(get_admin_user),
):
    """List anomaly flags with optional filters (admin only)."""
    query = select(AnomalyFlag).order_by(AnomalyFlag.created_at.desc()).limit(limit).offset(offset)

    if resolved is not None:
        query = query.where(AnomalyFlag.resolved == resolved)
    if severity:
        query = query.where(AnomalyFlag.severity == severity)

    result = await db.execute(query)
    flags = result.scalars().all()

    items = []
    for flag in flags:
        user = await db.get(User, flag.user_id)
        resolved_by_user = await db.get(User, flag.resolved_by) if flag.resolved_by else None

        items.append({
            "id": str(flag.id),
            "user": {
                "id": str(user.id),
                "full_name": user.full_name,
                "email": user.email,
            } if user else None,
            "completion_id": str(flag.completion_id) if flag.completion_id else None,
            "flag_type": flag.flag_type,
            "severity": flag.severity,
            "description": flag.description,
            "auto_detected": flag.auto_detected,
            "resolved": flag.resolved,
            "resolved_by": {
                "id": str(resolved_by_user.id),
                "full_name": resolved_by_user.full_name,
            } if resolved_by_user else None,
            "resolved_at": flag.resolved_at.isoformat() if flag.resolved_at else None,
            "resolution_note": flag.resolution_note,
            "created_at": flag.created_at.isoformat(),
        })

    return items


@router.put("/anomalies/{anomaly_id}/resolve")
async def resolve_anomaly(
    anomaly_id: str,
    req: ResolveAnomalyRequest,
    db: AsyncSession = Depends(get_db),
    admin: User = Depends(get_admin_user),
):
    """Resolve an anomaly flag — approve (dismiss) or reject (confirm anomaly)."""
    flag = await db.get(AnomalyFlag, UUID(anomaly_id))
    if not flag:
        raise HTTPException(status_code=404, detail="Anomaly flag not found")

    if flag.resolved:
        raise HTTPException(status_code=400, detail="Anomaly is already resolved")

    flag.resolved = True
    flag.resolved_by = admin.id
    flag.resolved_at = datetime.now(timezone.utc)
    flag.resolution_note = req.note

    # If approved (dismissed as false positive) and XP was held, release it
    if req.approve and flag.completion_id:
        completion = await db.get(ActivityCompletion, flag.completion_id)
        if completion and completion.status == "flagged":
            completion.status = "completed"
            completion.flagged_reason = None
            # Re-award XP to user
            user = await db.get(User, completion.user_id)
            if user and completion.xp_awarded > 0:
                user.total_xp += completion.xp_awarded
                if completion.trust_tier in (1, 2):
                    user.verified_xp += completion.xp_awarded

    # If rejected (confirmed anomaly), ensure completion stays flagged
    if not req.approve and flag.completion_id:
        completion = await db.get(ActivityCompletion, flag.completion_id)
        if completion:
            completion.status = "flagged"
            completion.flagged_reason = f"Confirmed by admin: {req.note or flag.description}"

    await db.flush()

    return {
        "id": str(flag.id),
        "resolved": True,
        "approved": req.approve,
        "resolved_by": admin.full_name,
        "resolution_note": flag.resolution_note,
        "resolved_at": flag.resolved_at.isoformat(),
    }


# --- Verification Queue ---

@router.get("/verification-queue")
async def list_verification_queue(
    status: str | None = Query("pending", description="Filter by status: pending, approved, rejected"),
    limit: int = Query(50, le=200),
    offset: int = Query(0, ge=0),
    db: AsyncSession = Depends(get_db),
    admin: User = Depends(get_admin_user),
):
    """List verification requests (admin only)."""
    query = (
        select(VerificationRequest)
        .order_by(VerificationRequest.created_at.desc())
        .limit(limit)
        .offset(offset)
    )
    if status:
        query = query.where(VerificationRequest.status == status)

    result = await db.execute(query)
    requests = result.scalars().all()

    items = []
    for vr in requests:
        user = await db.get(User, vr.user_id)
        completion = await db.get(ActivityCompletion, vr.completion_id)
        activity = await db.get(Activity, completion.activity_id) if completion else None
        reviewed_by_user = await db.get(User, vr.reviewed_by) if vr.reviewed_by else None

        items.append({
            "id": str(vr.id),
            "user": {
                "id": str(user.id),
                "full_name": user.full_name,
                "email": user.email,
            } if user else None,
            "completion": {
                "id": str(completion.id),
                "activity_title": activity.title if activity else None,
                "xp_awarded": completion.xp_awarded,
                "trust_tier": completion.trust_tier,
                "status": completion.status,
            } if completion else None,
            "evidence_url": vr.evidence_url,
            "evidence_type": vr.evidence_type,
            "notes": vr.notes,
            "status": vr.status,
            "reviewed_by": {
                "id": str(reviewed_by_user.id),
                "full_name": reviewed_by_user.full_name,
            } if reviewed_by_user else None,
            "reviewed_at": vr.reviewed_at.isoformat() if vr.reviewed_at else None,
            "review_note": vr.review_note,
            "created_at": vr.created_at.isoformat(),
        })

    return items


@router.put("/verification-queue/{request_id}")
async def review_verification(
    request_id: str,
    req: ReviewVerificationRequest,
    db: AsyncSession = Depends(get_db),
    admin: User = Depends(get_admin_user),
):
    """Approve or reject a verification request (admin only)."""
    vr = await db.get(VerificationRequest, UUID(request_id))
    if not vr:
        raise HTTPException(status_code=404, detail="Verification request not found")

    if vr.status != "pending":
        raise HTTPException(status_code=400, detail=f"Request is already {vr.status}")

    vr.status = "approved" if req.approve else "rejected"
    vr.reviewed_by = admin.id
    vr.reviewed_at = datetime.now(timezone.utc)
    vr.review_note = req.note

    # Update the linked completion
    completion = await db.get(ActivityCompletion, vr.completion_id)
    if completion:
        if req.approve:
            completion.status = "verified"
            completion.verified_by = admin.id
            completion.verification_note = req.note
            # Award XP for Tier 3 self-reported (was 0 XP until approved)
            if completion.trust_tier == 3 and completion.xp_awarded == 0:
                activity = await db.get(Activity, completion.activity_id)
                if activity:
                    completion.xp_awarded = activity.xp_value
                    user = await db.get(User, completion.user_id)
                    if user:
                        user.total_xp += activity.xp_value
                        # Tier 3 verified stays as unverified XP (only Tier 1+2 count)
        else:
            completion.status = "flagged"
            completion.flagged_reason = f"Verification rejected: {req.note or 'No reason given'}"

    await db.flush()

    return {
        "id": str(vr.id),
        "status": vr.status,
        "approved": req.approve,
        "reviewed_by": admin.full_name,
        "review_note": vr.review_note,
        "reviewed_at": vr.reviewed_at.isoformat(),
    }


# --- XP Audit Trail ---

@router.get("/xp-audit")
async def xp_audit(
    limit: int = Query(50, le=200),
    offset: int = Query(0, ge=0),
    trust_tier: int | None = Query(None, description="Filter by trust tier: 1, 2, or 3"),
    user_id: str | None = Query(None, description="Filter by user ID"),
    db: AsyncSession = Depends(get_db),
    admin: User = Depends(get_admin_user),
):
    """XP audit trail — all completions with trust tier info (admin only)."""
    query = (
        select(ActivityCompletion)
        .where(ActivityCompletion.status.in_(["completed", "verified", "flagged"]))
        .order_by(ActivityCompletion.updated_at.desc())
        .limit(limit)
        .offset(offset)
    )

    if trust_tier is not None:
        query = query.where(ActivityCompletion.trust_tier == trust_tier)
    if user_id:
        query = query.where(ActivityCompletion.user_id == UUID(user_id))

    result = await db.execute(query)
    completions = result.scalars().all()

    items = []
    for c in completions:
        user = await db.get(User, c.user_id)
        activity = await db.get(Activity, c.activity_id)

        items.append({
            "id": str(c.id),
            "user": {
                "id": str(user.id),
                "full_name": user.full_name,
                "email": user.email,
            } if user else None,
            "activity": {
                "id": str(activity.id),
                "title": activity.title,
                "category": activity.category,
                "platform": activity.platform,
                "xp_value": activity.xp_value,
            } if activity else None,
            "status": c.status,
            "xp_awarded": c.xp_awarded,
            "trust_tier": c.trust_tier,
            "source": c.source,
            "source_detail": c.source_detail,
            "period_key": c.period_key,
            "flagged_reason": c.flagged_reason,
            "completed_at": c.completed_at.isoformat() if c.completed_at else None,
            "updated_at": c.updated_at.isoformat(),
        })

    # Summary stats
    total_xp_result = await db.execute(
        select(
            ActivityCompletion.trust_tier,
            func.count(ActivityCompletion.id),
            func.coalesce(func.sum(ActivityCompletion.xp_awarded), 0),
        )
        .where(ActivityCompletion.status.in_(["completed", "verified"]))
        .group_by(ActivityCompletion.trust_tier)
    )
    tier_summary = {}
    for tier, count, xp in total_xp_result.all():
        tier_summary[f"tier_{tier}"] = {"count": count, "total_xp": xp}

    return {
        "items": items,
        "tier_summary": tier_summary,
    }
