"""
Boundary Commission API Endpoints
Extends the main API with boundary-specific functionality
"""

from fastapi import APIRouter, Query, HTTPException, Depends, status, File, UploadFile, Form
from typing import Optional, List, Any
from datetime import date, datetime
import os
import uuid
import tempfile
from fastapi.responses import FileResponse

from backend.api.boundary_models import (
    Boundary, BoundaryCoordinate, BoundaryMarker, BoundaryDispute,
    DisputeEvidence, BoundarySurvey, BoundaryTreaty, Stakeholder,
    BoundarySearchResult, DisputeSearchResult, BoundaryType, DisputeStatus
)
from backend.services.browser_service import (
    AumentumBrowserService,
    DEFAULT_DB_CONFIG,
    DEFAULT_CONTENTSTORE_BASE,
)
from backend.services.boundary_document_service import BoundaryDocumentService
from backend.auth.dependencies import get_current_user

# Optional auth: use main app's get_current_user (returns None when no/invalid token)
get_current_user_optional = get_current_user

router = APIRouter(prefix="/boundary", tags=["Boundary Commission"])

service = AumentumBrowserService(
    db_config=DEFAULT_DB_CONFIG,
    contentstore_base=DEFAULT_CONTENTSTORE_BASE
)

document_service = BoundaryDocumentService(
    contentstore_base=DEFAULT_CONTENTSTORE_BASE,
    db_config=DEFAULT_DB_CONFIG
)


@router.get("/boundaries")
async def list_boundaries(
    boundary_number: Optional[str] = Query(None, description="Boundary number filter"),
    name: Optional[str] = Query(None, description="Boundary name filter"),
    boundary_type: Optional[str] = Query(None, description="Boundary type filter"),
    state: Optional[str] = Query(None, description="State filter"),
    status: Optional[str] = Query(None, description="Status filter"),
    limit: int = Query(100, ge=1, le=1000),
    offset: int = Query(0, ge=0),
    current_user: Any = Depends(get_current_user_optional)
):
    """List all boundaries with optional filters."""
    try:
        conn = service._get_db_connection()
        cursor = conn.cursor()
        query = "SELECT * FROM boundary WHERE 1=1"
        params = []
        if boundary_number:
            query += " AND boundary_number LIKE %s"
            params.append(f"%{boundary_number}%")
        if name:
            query += " AND name LIKE %s"
            params.append(f"%{name}%")
        if boundary_type:
            query += " AND boundary_type = %s"
            params.append(boundary_type)
        if state:
            query += " AND (state_a LIKE %s OR state_b LIKE %s)"
            params.extend([f"%{state}%", f"%{state}%"])
        if status:
            query += " AND status = %s"
            params.append(status)
        query += " ORDER BY boundary_number LIMIT %s OFFSET %s"
        params.extend([limit, offset])
        cursor.execute(query, params)
        rows = cursor.fetchall()
        boundaries = [
            Boundary(
                id=row[0], boundary_number=row[1], name=row[2], boundary_type=row[3],
                state_a=row[4], state_b=row[5], length_km=row[6], established_date=row[7],
                legal_basis=row[8], status=row[9], description=row[10],
                created_at=row[11], updated_at=row[12]
            )
            for row in rows
        ]
        cursor.close()
        conn.close()
        return boundaries
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Error fetching boundaries: {str(e)}")


@router.get("/boundaries/{boundary_number}")
async def get_boundary_details(
    boundary_number: str,
    current_user: Any = Depends(get_current_user_optional)
):
    """Get detailed information about a specific boundary."""
    try:
        conn = service._get_db_connection()
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM boundary WHERE boundary_number = %s", (boundary_number,))
        boundary_row = cursor.fetchone()
        if not boundary_row:
            raise HTTPException(status_code=404, detail="Boundary not found")
        boundary = Boundary(
            id=boundary_row[0], boundary_number=boundary_row[1], name=boundary_row[2],
            boundary_type=boundary_row[3], state_a=boundary_row[4], state_b=boundary_row[5],
            length_km=boundary_row[6], established_date=boundary_row[7], legal_basis=boundary_row[8],
            status=boundary_row[9], description=boundary_row[10],
            created_at=boundary_row[11], updated_at=boundary_row[12]
        )
        cursor.execute(
            "SELECT * FROM boundary_coordinate WHERE boundary_id = %s ORDER BY sequence",
            (boundary.id,)
        )
        coordinates = [
            BoundaryCoordinate(
                id=row[0], boundary_id=row[1], sequence=row[2], latitude=row[3], longitude=row[4],
                elevation=row[5], coordinate_system=row[6] or "WGS84", accuracy=row[7],
                survey_date=row[8], survey_method=row[9]
            )
            for row in cursor.fetchall()
        ]
        cursor.execute("SELECT * FROM boundary_marker WHERE boundary_id = %s", (boundary.id,))
        markers = [
            BoundaryMarker(
                id=row[0], boundary_id=row[1], marker_number=row[2], marker_type=row[3],
                latitude=row[4], longitude=row[5], elevation=row[6], marker_condition=row[7],
                last_inspection_date=row[8], description=row[9],
                photos=row[10].split(',') if row[10] else []
            )
            for row in cursor.fetchall()
        ]
        cursor.execute(
            "SELECT * FROM boundary_dispute WHERE boundary_id = %s AND status != 'closed'",
            (boundary.id,)
        )
        active_disputes = [
            BoundaryDispute(
                id=row[0], dispute_number=row[1], boundary_id=row[2], title=row[3], description=row[4],
                status=row[5], claimant_a=row[6], claimant_b=row[7], disputed_area_km2=row[8],
                filed_date=row[9], resolution_date=row[10], resolution_summary=row[11],
                legal_reference=row[12], assigned_officer=row[13], priority=row[14],
                created_at=row[15], updated_at=row[16]
            )
            for row in cursor.fetchall()
        ]
        cursor.execute(
            "SELECT * FROM boundary_survey WHERE boundary_id = %s ORDER BY survey_date DESC LIMIT 5",
            (boundary.id,)
        )
        recent_surveys = [
            BoundarySurvey(
                id=row[0], boundary_id=row[1], survey_number=row[2], survey_date=row[3],
                survey_team=row[4], survey_method=row[5], accuracy=row[6], report_url=row[7],
                notes=row[8], approved=row[9], approved_by=row[10], approved_date=row[11]
            )
            for row in cursor.fetchall()
        ]
        cursor.execute("SELECT * FROM boundary_treaty WHERE boundary_id = %s", (boundary.id,))
        related_treaties = [
            BoundaryTreaty(
                id=row[0], boundary_id=row[1], treaty_number=row[2], title=row[3],
                signing_date=row[4], effective_date=row[5],
                parties=row[6].split(',') if row[6] else [],
                document_url=row[7], summary=row[8], status=row[9]
            )
            for row in cursor.fetchall()
        ]
        cursor.close()
        conn.close()
        return BoundarySearchResult(
            boundary=boundary, coordinates=coordinates, markers=markers,
            active_disputes=active_disputes, recent_surveys=recent_surveys,
            related_treaties=related_treaties
        )
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Error fetching boundary details: {str(e)}")


@router.get("/disputes")
async def list_disputes(
    dispute_number: Optional[str] = Query(None),
    title: Optional[str] = Query(None),
    status: Optional[str] = Query(None),
    state: Optional[str] = Query(None),
    priority: Optional[str] = Query(None),
    claimant_a: Optional[str] = Query(None),
    claimant_b: Optional[str] = Query(None),
    limit: int = Query(100, ge=1, le=1000),
    offset: int = Query(0, ge=0),
    current_user: Any = Depends(get_current_user_optional)
):
    """List boundary disputes with optional filters."""
    try:
        conn = service._get_db_connection()
        cursor = conn.cursor()
        query = "SELECT * FROM boundary_dispute WHERE 1=1"
        params = []
        if dispute_number:
            query += " AND dispute_number LIKE %s"
            params.append(f"%{dispute_number}%")
        if title:
            query += " AND title LIKE %s"
            params.append(f"%{title}%")
        if status:
            query += " AND status = %s"
            params.append(status)
        if state:
            query += " AND (claimant_a LIKE %s OR claimant_b LIKE %s)"
            params.extend([f"%{state}%", f"%{state}%"])
        if priority:
            query += " AND priority = %s"
            params.append(priority)
        if claimant_a:
            query += " AND claimant_a LIKE %s"
            params.append(f"%{claimant_a}%")
        if claimant_b:
            query += " AND claimant_b LIKE %s"
            params.append(f"%{claimant_b}%")
        query += " ORDER BY filed_date DESC LIMIT %s OFFSET %s"
        params.extend([limit, offset])
        cursor.execute(query, params)
        rows = cursor.fetchall()
        disputes = [
            BoundaryDispute(
                id=row[0], dispute_number=row[1], boundary_id=row[2], title=row[3], description=row[4],
                status=row[5], claimant_a=row[6], claimant_b=row[7], disputed_area_km2=row[8],
                filed_date=row[9], resolution_date=row[10], resolution_summary=row[11],
                legal_reference=row[12], assigned_officer=row[13], priority=row[14],
                created_at=row[15], updated_at=row[16]
            )
            for row in rows
        ]
        cursor.close()
        conn.close()
        return disputes
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Error fetching disputes: {str(e)}")


@router.get("/disputes/{dispute_number}")
async def get_dispute_details(
    dispute_number: str,
    current_user: Any = Depends(get_current_user_optional)
):
    """Get detailed information about a specific dispute."""
    try:
        conn = service._get_db_connection()
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM boundary_dispute WHERE dispute_number = %s", (dispute_number,))
        dispute_row = cursor.fetchone()
        if not dispute_row:
            raise HTTPException(status_code=404, detail="Dispute not found")
        dispute = BoundaryDispute(
            id=dispute_row[0], dispute_number=dispute_row[1], boundary_id=dispute_row[2],
            title=dispute_row[3], description=dispute_row[4], status=dispute_row[5],
            claimant_a=dispute_row[6], claimant_b=dispute_row[7], disputed_area_km2=dispute_row[8],
            filed_date=dispute_row[9], resolution_date=dispute_row[10],
            resolution_summary=dispute_row[11], legal_reference=dispute_row[12],
            assigned_officer=dispute_row[13], priority=dispute_row[14],
            created_at=dispute_row[15], updated_at=dispute_row[16]
        )
        boundary = None
        if dispute.boundary_id:
            cursor.execute("SELECT * FROM boundary WHERE id = %s", (dispute.boundary_id,))
            boundary_row = cursor.fetchone()
            if boundary_row:
                boundary = Boundary(
                    id=boundary_row[0], boundary_number=boundary_row[1], name=boundary_row[2],
                    boundary_type=boundary_row[3], state_a=boundary_row[4], state_b=boundary_row[5],
                    length_km=boundary_row[6], established_date=boundary_row[7], legal_basis=boundary_row[8],
                    status=boundary_row[9], description=boundary_row[10],
                    created_at=boundary_row[11], updated_at=boundary_row[12]
                )
        cursor.execute(
            "SELECT * FROM dispute_evidence WHERE dispute_id = %s ORDER BY is_primary DESC, submitted_date DESC",
            (dispute.id,)
        )
        evidence = [
            DisputeEvidence(
                id=row[0], dispute_id=row[1], document_type=row[2], title=row[3],
                description=row[4], document_url=row[5], file_path=row[6],
                submitted_by=row[7], submitted_date=row[8], is_primary=row[9]
            )
            for row in cursor.fetchall()
        ]
        cursor.execute(
            "SELECT s.* FROM stakeholder s JOIN dispute_stakeholder ds ON s.id = ds.stakeholder_id WHERE ds.dispute_id = %s",
            (dispute.id,)
        )
        stakeholders = [
            Stakeholder(
                id=row[0], name=row[1], entity_type=row[2], contact_person=row[3],
                email=row[4], phone=row[5], address=row[6], role=row[7], notes=row[8]
            )
            for row in cursor.fetchall()
        ]
        timeline = [
            {"date": dispute.filed_date, "event": "Dispute filed", "actor": dispute.claimant_a},
            {"date": dispute.updated_at or dispute.created_at, "event": "Last updated", "actor": None}
        ]
        if dispute.resolution_date:
            timeline.append({
                "date": dispute.resolution_date,
                "event": "Dispute resolved",
                "actor": dispute.assigned_officer
            })
        cursor.close()
        conn.close()
        return DisputeSearchResult(
            dispute=dispute, boundary=boundary, evidence=evidence,
            stakeholders=stakeholders, timeline=timeline
        )
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Error fetching dispute details: {str(e)}")


@router.post("/boundaries")
async def create_boundary(
    boundary: Boundary,
    current_user: Any = Depends(get_current_user_optional)
):
    """Create a new boundary record."""
    return boundary


@router.post("/disputes")
async def create_dispute(
    dispute: BoundaryDispute,
    current_user: Any = Depends(get_current_user_optional)
):
    """Create a new boundary dispute case."""
    return dispute


@router.post("/documents/upload")
async def upload_boundary_document(
    file: UploadFile = File(...),
    document_number: Optional[str] = Form(None),
    pseudo_document_number: Optional[str] = Form(None),
    document_type: str = Form(...),
    title: str = Form(...),
    description: Optional[str] = Form(None),
    visibility: str = Form("open"),
    related_boundary_id: Optional[int] = Form(None),
    related_dispute_id: Optional[int] = Form(None),
    related_survey_id: Optional[int] = Form(None),
    related_treaty_id: Optional[int] = Form(None),
    uploaded_by: Optional[str] = Form(None),
    current_user: Any = Depends(get_current_user_optional)
):
    """Upload and index a boundary document. Supports PDF, JPEG, PNG, .bin."""
    try:
        # Only Boundary File and Administrative File are allowed (dropdown has just these two).
        document_type_map = {
            'boundary_file': 'boundary_file',
            'administrative_file': 'administrative_file',
        }
        normalized_document_type = document_type_map.get(
            (document_type or '').strip().lower(), 'administrative_file'
        )
        normalized_visibility = (visibility or "open").lower()
        if normalized_visibility not in ("open", "secret"):
            normalized_visibility = "open"
        file_extension = os.path.splitext(file.filename)[1] if file.filename else '.bin'
        safe_filename = file.filename.replace('/', '_').replace('\\', '_') if file.filename else 'uploaded_file'
        temp_path = os.path.join(tempfile.gettempdir(), f"boundary_upload_{uuid.uuid4().hex}{file_extension}")
        try:
            content = await file.read()
            with open(temp_path, "wb") as f:
                f.write(content)
            result = document_service.index_document(
                document_number=document_number,
                document_type=normalized_document_type,
                title=title,
                file_path=temp_path,
                related_boundary_id=related_boundary_id,
                related_dispute_id=related_dispute_id,
                related_survey_id=related_survey_id,
                related_treaty_id=related_treaty_id,
                description=description,
                uploaded_by=uploaded_by or (current_user.username if current_user else None),
                visibility=normalized_visibility,
                pseudo_document_number=pseudo_document_number,
            )
            return result
        finally:
            if os.path.exists(temp_path):
                try:
                    os.remove(temp_path)
                except Exception:
                    pass
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Error uploading document: {str(e)}")


@router.get("/documents/pdf-by-document-number")
async def get_boundary_document_pdf(
    document_number: str = Query(..., description="Boundary document number"),
    current_user: Any = Depends(get_current_user_optional)
):
    """Get boundary document as PDF."""
    result = document_service.fetch_pdf_by_document_number(document_number)
    if result.get("error"):
        raise HTTPException(status_code=404, detail=result["error"])
    if not result.get("pdf_path") or not os.path.exists(result["pdf_path"]):
        raise HTTPException(status_code=404, detail="PDF not found")
    return FileResponse(
        result["pdf_path"],
        media_type="application/pdf",
        filename=os.path.basename(result["pdf_path"])
    )


@router.get("/documents/list")
async def list_boundary_documents(
    related_boundary_id: Optional[int] = None,
    related_dispute_id: Optional[int] = None,
    document_type: Optional[str] = None,
    limit: int = Query(100, ge=1, le=1000),
    offset: int = Query(0, ge=0),
    current_user: Any = Depends(get_current_user_optional)
):
    """List boundary documents with filters."""
    try:
        conn = service._get_db_connection()
        cursor = conn.cursor()
        query = "SELECT * FROM boundary_document WHERE 1=1"
        params = []
        if related_boundary_id:
            query += " AND related_boundary_id = %s"
            params.append(related_boundary_id)
        if related_dispute_id:
            query += " AND related_dispute_id = %s"
            params.append(related_dispute_id)
        if document_type:
            query += " AND document_type = %s"
            params.append(document_type)
        query += " ORDER BY uploaded_date DESC LIMIT %s OFFSET %s"
        params.extend([limit, offset])
        cursor.execute(query, params)
        columns = [col[0] for col in cursor.description]
        rows = cursor.fetchall()
        documents = []
        for row in rows:
            doc_dict = dict(zip(columns, row))
            for k in ('uploaded_date', 'created_at', 'updated_at'):
                if doc_dict.get(k) and hasattr(doc_dict[k], 'isoformat'):
                    doc_dict[k] = doc_dict[k].isoformat()
            documents.append(doc_dict)
        cursor.close()
        conn.close()
        return {"count": len(documents), "documents": documents}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Error listing documents: {str(e)}")
