"""Pending identifications endpoints for approval workflow."""

from __future__ import annotations

from datetime import date, datetime
from typing import Annotated, Optional

from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel, ConfigDict
from sqlalchemy import text
from sqlalchemy.orm import Session

from src.web.db.session import get_auth_db, get_db
from src.web.db.models import Face, Person, PersonEncoding
from src.web.api.users import get_current_admin_user

router = APIRouter(prefix="/pending-identifications", tags=["pending-identifications"])


class PendingIdentificationResponse(BaseModel):
    """Pending identification DTO returned from API."""

    model_config = ConfigDict(from_attributes=True, protected_namespaces=())

    id: int
    face_id: int
    photo_id: Optional[int] = None
    user_id: int
    user_name: Optional[str] = None
    user_email: str
    first_name: str
    last_name: str
    middle_name: Optional[str] = None
    maiden_name: Optional[str] = None
    date_of_birth: Optional[date] = None
    status: str
    created_at: str
    updated_at: str


class PendingIdentificationsListResponse(BaseModel):
    """List of pending identifications."""

    model_config = ConfigDict(protected_namespaces=())

    items: list[PendingIdentificationResponse]
    total: int


class ApproveDenyDecision(BaseModel):
    """Decision for a single pending identification."""

    model_config = ConfigDict(protected_namespaces=())

    id: int
    decision: str  # 'approve' or 'deny'


class ApproveDenyRequest(BaseModel):
    """Request to approve/deny multiple pending identifications."""

    model_config = ConfigDict(protected_namespaces=())

    decisions: list[ApproveDenyDecision]


class ApproveDenyResponse(BaseModel):
    """Response from approve/deny operation."""

    model_config = ConfigDict(protected_namespaces=())

    approved: int
    denied: int
    errors: list[str]


@router.get("", response_model=PendingIdentificationsListResponse)
def list_pending_identifications(
    current_admin: Annotated[dict, Depends(get_current_admin_user)],
    include_denied: bool = False,
    db: Session = Depends(get_auth_db),
    main_db: Session = Depends(get_db),
) -> PendingIdentificationsListResponse:
    """List all pending identifications from the auth database.
    
    This endpoint reads from the separate auth database (DATABASE_URL_AUTH)
    and returns all pending identifications from the pending_identifications table.
    By default, only shows records with status='pending' for approval.
    Set include_denied=True to also show denied records.
    """
    try:
        # Query pending_identifications from auth database using raw SQL
        # Join with users table to get user name/email
        # Filter by status='pending' to show only records awaiting approval
        # Optionally include denied records if include_denied is True
        if include_denied:
            result = db.execute(text("""
                SELECT 
                    pi.id,
                    pi.face_id,
                    pi.user_id,
                    u.name as user_name,
                    u.email as user_email,
                    pi.first_name,
                    pi.last_name,
                    pi.middle_name,
                    pi.maiden_name,
                    pi.date_of_birth,
                    pi.status,
                    pi.created_at,
                    pi.updated_at
                FROM pending_identifications pi
                LEFT JOIN users u ON pi.user_id = u.id
                WHERE pi.status IN ('pending', 'denied')
                ORDER BY pi.status ASC, pi.last_name ASC, pi.first_name ASC, pi.created_at DESC
            """))
        else:
            result = db.execute(text("""
                SELECT 
                    pi.id,
                    pi.face_id,
                    pi.user_id,
                    u.name as user_name,
                    u.email as user_email,
                    pi.first_name,
                    pi.last_name,
                    pi.middle_name,
                    pi.maiden_name,
                    pi.date_of_birth,
                    pi.status,
                    pi.created_at,
                    pi.updated_at
                FROM pending_identifications pi
                LEFT JOIN users u ON pi.user_id = u.id
                WHERE pi.status = 'pending'
                ORDER BY pi.last_name ASC, pi.first_name ASC, pi.created_at DESC
            """))
        
        rows = result.fetchall()
        items = []
        for row in rows:
            # Get photo_id from main database
            photo_id = None
            face = main_db.query(Face).filter(Face.id == row.face_id).first()
            if face:
                photo_id = face.photo_id
            
            items.append(PendingIdentificationResponse(
                id=row.id,
                face_id=row.face_id,
                photo_id=photo_id,
                user_id=row.user_id,
                user_name=row.user_name,
                user_email=row.user_email,
                first_name=row.first_name,
                last_name=row.last_name,
                middle_name=row.middle_name,
                maiden_name=row.maiden_name,
                date_of_birth=row.date_of_birth,
                status=row.status,
                created_at=str(row.created_at) if row.created_at else '',
                updated_at=str(row.updated_at) if row.updated_at else '',
            ))
        
        return PendingIdentificationsListResponse(items=items, total=len(items))
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Error reading from auth database: {str(e)}"
        )


@router.post("/approve-deny", response_model=ApproveDenyResponse)
def approve_deny_pending_identifications(
    current_admin: Annotated[dict, Depends(get_current_admin_user)],
    request: ApproveDenyRequest,
    auth_db: Session = Depends(get_auth_db),
    main_db: Session = Depends(get_db),
) -> ApproveDenyResponse:
    """Approve or deny pending identifications.
    
    For approved identifications:
    - Updates status in auth database to 'approved'
    - Identifies the face in main database
    - Creates person if needed
    
    For denied identifications:
    - Updates status in auth database to 'denied'
    """
    approved_count = 0
    denied_count = 0
    errors = []
    
    for decision in request.decisions:
        try:
            # Get pending identification from auth database
            # Allow processing of both 'pending' and 'denied' status (to allow re-approval)
            result = auth_db.execute(text("""
                SELECT 
                    pi.id,
                    pi.face_id,
                    pi.first_name,
                    pi.last_name,
                    pi.middle_name,
                    pi.maiden_name,
                    pi.date_of_birth
                FROM pending_identifications pi
                WHERE pi.id = :id AND pi.status IN ('pending', 'denied')
            """), {"id": decision.id})
            
            row = result.fetchone()
            if not row:
                errors.append(f"Pending identification {decision.id} not found or already processed")
                continue
            
            if decision.decision == 'approve':
                # Identify the face in main database
                face = main_db.query(Face).filter(Face.id == row.face_id).first()
                if not face:
                    errors.append(f"Face {row.face_id} not found in main database")
                    # Still update status to denied since we can't process it
                    auth_db.execute(text("""
                        UPDATE pending_identifications
                        SET status = 'denied', updated_at = :updated_at
                        WHERE id = :id
                    """), {"id": decision.id, "updated_at": datetime.utcnow()})
                    auth_db.commit()
                    denied_count += 1
                    continue
                
                # Check if person already exists (by name and DOB)
                # Match the unique constraint: first_name, last_name, middle_name, maiden_name, date_of_birth
                person = None
                if row.date_of_birth:
                    # Build query with proper None handling
                    query = main_db.query(Person).filter(
                        Person.first_name == row.first_name,
                        Person.last_name == row.last_name,
                        Person.date_of_birth == row.date_of_birth
                    )
                    # Handle optional fields - use IS NULL for None values
                    if row.middle_name:
                        query = query.filter(Person.middle_name == row.middle_name)
                    else:
                        query = query.filter(Person.middle_name.is_(None))
                    
                    if row.maiden_name:
                        query = query.filter(Person.maiden_name == row.maiden_name)
                    else:
                        query = query.filter(Person.maiden_name.is_(None))
                    
                    person = query.first()
                
                # Create person if doesn't exist
                created_person = False
                if not person:
                    if not row.date_of_birth:
                        errors.append(f"Pending identification {decision.id} missing date_of_birth (required for person creation)")
                        auth_db.execute(text("""
                            UPDATE pending_identifications
                            SET status = 'denied', updated_at = :updated_at
                            WHERE id = :id
                        """), {"id": decision.id, "updated_at": datetime.utcnow()})
                        auth_db.commit()
                        denied_count += 1
                        continue
                    
                    person = Person(
                        first_name=row.first_name,
                        last_name=row.last_name,
                        middle_name=row.middle_name,
                        maiden_name=row.maiden_name,
                        date_of_birth=row.date_of_birth,
                    )
                    main_db.add(person)
                    main_db.flush()  # get person.id
                    created_person = True
                
                # Link face to person
                face.person_id = person.id
                main_db.add(face)
                
                # Insert person_encoding
                pe = PersonEncoding(
                    person_id=person.id,
                    face_id=face.id,
                    encoding=face.encoding,
                    quality_score=face.quality_score,
                    detector_backend=face.detector_backend,
                    model_name=face.model_name,
                )
                main_db.add(pe)
                main_db.commit()
                
                # Update status in auth database
                auth_db.execute(text("""
                    UPDATE pending_identifications
                    SET status = 'approved', updated_at = :updated_at
                    WHERE id = :id
                """), {"id": decision.id, "updated_at": datetime.utcnow()})
                auth_db.commit()
                
                approved_count += 1
                
            elif decision.decision == 'deny':
                # Update status to denied
                auth_db.execute(text("""
                    UPDATE pending_identifications
                    SET status = 'denied', updated_at = :updated_at
                    WHERE id = :id
                """), {"id": decision.id, "updated_at": datetime.utcnow()})
                auth_db.commit()
                
                denied_count += 1
            else:
                errors.append(f"Invalid decision '{decision.decision}' for pending identification {decision.id}")
                
        except Exception as e:
            errors.append(f"Error processing pending identification {decision.id}: {str(e)}")
            # Rollback any partial changes
            main_db.rollback()
            auth_db.rollback()
    
    return ApproveDenyResponse(
        approved=approved_count,
        denied=denied_count,
        errors=errors
    )

