"""
POI Refresh Jobs API Endpoints

REST API for managing POI refresh background jobs.
"""

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, desc
from typing import List, Optional
from datetime import datetime, timezone
from pydantic import BaseModel, Field
import structlog
import uuid

from app.core.database import get_db
from app.services.poi_refresh_service import POIRefreshService
from app.services.poi_scheduler import get_scheduler
from app.models.poi_refresh_job import POIRefreshJob

logger = structlog.get_logger()

router = APIRouter(prefix="/poi-refresh-jobs", tags=["POI Refresh Jobs"])


# Response Models
class POIRefreshJobResponse(BaseModel):
    """POI refresh job response"""
    id: str
    tenant_id: str
    status: str
    scheduled_at: datetime
    started_at: Optional[datetime] = None
    completed_at: Optional[datetime] = None
    attempt_count: int
    max_attempts: int
    pois_detected: Optional[int] = None
    changes_detected: bool = False
    change_summary: Optional[dict] = None
    error_message: Optional[str] = None
    next_scheduled_at: Optional[datetime] = None
    duration_seconds: Optional[float] = None
    is_overdue: bool
    can_retry: bool

    class Config:
        from_attributes = True


class ScheduleJobRequest(BaseModel):
    """Schedule POI refresh job request"""
    tenant_id: str = Field(..., description="Tenant UUID")
    latitude: float = Field(..., ge=-90, le=90, description="Bakery latitude")
    longitude: float = Field(..., ge=-180, le=180, description="Bakery longitude")
    scheduled_at: Optional[datetime] = Field(None, description="When to run (default: 180 days from now)")


class JobExecutionResult(BaseModel):
    """Job execution result"""
    status: str
    job_id: str
    message: Optional[str] = None
    pois_detected: Optional[int] = None
    changes_detected: Optional[bool] = None
    change_summary: Optional[dict] = None
    duration_seconds: Optional[float] = None
    next_scheduled_at: Optional[str] = None
    error: Optional[str] = None
    attempt: Optional[int] = None
    can_retry: Optional[bool] = None


# Endpoints
@router.post(
    "/schedule",
    response_model=POIRefreshJobResponse,
    summary="Schedule POI refresh job",
    description="Schedule a background job to refresh POI context for a tenant"
)
async def schedule_refresh_job(
    request: ScheduleJobRequest,
    db: AsyncSession = Depends(get_db)
):
    """
    Schedule a POI refresh job for a tenant.

    Creates a background job that will detect POIs for the tenant's location
    at the scheduled time. Default schedule is 180 days from now.
    """
    try:
        tenant_uuid = uuid.UUID(request.tenant_id)
    except ValueError:
        raise HTTPException(status_code=400, detail="Invalid tenant_id format")

    try:
        poi_refresh_service = POIRefreshService()
        job = await poi_refresh_service.schedule_refresh_job(
            tenant_id=request.tenant_id,
            latitude=request.latitude,
            longitude=request.longitude,
            scheduled_at=request.scheduled_at,
            session=db
        )

        logger.info(
            "POI refresh job scheduled via API",
            tenant_id=request.tenant_id,
            job_id=str(job.id),
            scheduled_at=job.scheduled_at
        )

        return POIRefreshJobResponse(
            id=str(job.id),
            tenant_id=str(job.tenant_id),
            status=job.status,
            scheduled_at=job.scheduled_at,
            started_at=job.started_at,
            completed_at=job.completed_at,
            attempt_count=job.attempt_count,
            max_attempts=job.max_attempts,
            pois_detected=job.pois_detected,
            changes_detected=job.changes_detected,
            change_summary=job.change_summary,
            error_message=job.error_message,
            next_scheduled_at=job.next_scheduled_at,
            duration_seconds=job.duration_seconds,
            is_overdue=job.is_overdue,
            can_retry=job.can_retry
        )

    except Exception as e:
        logger.error(
            "Failed to schedule POI refresh job",
            tenant_id=request.tenant_id,
            error=str(e),
            exc_info=True
        )
        raise HTTPException(
            status_code=500,
            detail=f"Failed to schedule refresh job: {str(e)}"
        )


@router.get(
    "/{job_id}",
    response_model=POIRefreshJobResponse,
    summary="Get refresh job by ID",
    description="Retrieve details of a specific POI refresh job"
)
async def get_refresh_job(
    job_id: str,
    db: AsyncSession = Depends(get_db)
):
    """Get POI refresh job by ID"""
    try:
        job_uuid = uuid.UUID(job_id)
    except ValueError:
        raise HTTPException(status_code=400, detail="Invalid job_id format")

    result = await db.execute(
        select(POIRefreshJob).where(POIRefreshJob.id == job_uuid)
    )
    job = result.scalar_one_or_none()

    if not job:
        raise HTTPException(status_code=404, detail=f"Job not found: {job_id}")

    return POIRefreshJobResponse(
        id=str(job.id),
        tenant_id=str(job.tenant_id),
        status=job.status,
        scheduled_at=job.scheduled_at,
        started_at=job.started_at,
        completed_at=job.completed_at,
        attempt_count=job.attempt_count,
        max_attempts=job.max_attempts,
        pois_detected=job.pois_detected,
        changes_detected=job.changes_detected,
        change_summary=job.change_summary,
        error_message=job.error_message,
        next_scheduled_at=job.next_scheduled_at,
        duration_seconds=job.duration_seconds,
        is_overdue=job.is_overdue,
        can_retry=job.can_retry
    )


@router.get(
    "/tenant/{tenant_id}",
    response_model=List[POIRefreshJobResponse],
    summary="Get refresh jobs for tenant",
    description="Retrieve all POI refresh jobs for a specific tenant"
)
async def get_tenant_refresh_jobs(
    tenant_id: str,
    status: Optional[str] = Query(None, description="Filter by status"),
    limit: int = Query(50, ge=1, le=200, description="Maximum number of results"),
    db: AsyncSession = Depends(get_db)
):
    """Get all POI refresh jobs for a tenant"""
    try:
        tenant_uuid = uuid.UUID(tenant_id)
    except ValueError:
        raise HTTPException(status_code=400, detail="Invalid tenant_id format")

    query = select(POIRefreshJob).where(POIRefreshJob.tenant_id == tenant_uuid)

    if status:
        query = query.where(POIRefreshJob.status == status)

    query = query.order_by(desc(POIRefreshJob.scheduled_at)).limit(limit)

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

    return [
        POIRefreshJobResponse(
            id=str(job.id),
            tenant_id=str(job.tenant_id),
            status=job.status,
            scheduled_at=job.scheduled_at,
            started_at=job.started_at,
            completed_at=job.completed_at,
            attempt_count=job.attempt_count,
            max_attempts=job.max_attempts,
            pois_detected=job.pois_detected,
            changes_detected=job.changes_detected,
            change_summary=job.change_summary,
            error_message=job.error_message,
            next_scheduled_at=job.next_scheduled_at,
            duration_seconds=job.duration_seconds,
            is_overdue=job.is_overdue,
            can_retry=job.can_retry
        )
        for job in jobs
    ]


@router.post(
    "/{job_id}/execute",
    response_model=JobExecutionResult,
    summary="Execute refresh job",
    description="Manually trigger execution of a pending POI refresh job"
)
async def execute_refresh_job(
    job_id: str,
    db: AsyncSession = Depends(get_db)
):
    """Manually execute a POI refresh job"""
    try:
        job_uuid = uuid.UUID(job_id)
    except ValueError:
        raise HTTPException(status_code=400, detail="Invalid job_id format")

    try:
        poi_refresh_service = POIRefreshService()
        result = await poi_refresh_service.execute_refresh_job(
            job_id=job_id,
            session=db
        )

        logger.info(
            "POI refresh job executed via API",
            job_id=job_id,
            status=result["status"]
        )

        return JobExecutionResult(**result)

    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e))
    except Exception as e:
        logger.error(
            "Failed to execute POI refresh job",
            job_id=job_id,
            error=str(e),
            exc_info=True
        )
        raise HTTPException(
            status_code=500,
            detail=f"Failed to execute refresh job: {str(e)}"
        )


@router.post(
    "/process-pending",
    summary="Process all pending jobs",
    description="Manually trigger processing of all pending POI refresh jobs"
)
async def process_pending_jobs(
    max_concurrent: int = Query(5, ge=1, le=20, description="Max concurrent executions"),
    db: AsyncSession = Depends(get_db)
):
    """Process all pending POI refresh jobs"""
    try:
        poi_refresh_service = POIRefreshService()
        result = await poi_refresh_service.process_pending_jobs(
            max_concurrent=max_concurrent,
            session=db
        )

        logger.info(
            "Pending POI refresh jobs processed via API",
            total_jobs=result["total_jobs"],
            successful=result["successful"],
            failed=result["failed"]
        )

        return result

    except Exception as e:
        logger.error(
            "Failed to process pending POI refresh jobs",
            error=str(e),
            exc_info=True
        )
        raise HTTPException(
            status_code=500,
            detail=f"Failed to process pending jobs: {str(e)}"
        )


@router.get(
    "/pending",
    response_model=List[POIRefreshJobResponse],
    summary="Get pending jobs",
    description="Retrieve all pending POI refresh jobs that are due for execution"
)
async def get_pending_jobs(
    limit: int = Query(100, ge=1, le=500, description="Maximum number of results"),
    db: AsyncSession = Depends(get_db)
):
    """Get all pending POI refresh jobs"""
    try:
        poi_refresh_service = POIRefreshService()
        jobs = await poi_refresh_service.get_pending_jobs(
            limit=limit,
            session=db
        )

        return [
            POIRefreshJobResponse(
                id=str(job.id),
                tenant_id=str(job.tenant_id),
                status=job.status,
                scheduled_at=job.scheduled_at,
                started_at=job.started_at,
                completed_at=job.completed_at,
                attempt_count=job.attempt_count,
                max_attempts=job.max_attempts,
                pois_detected=job.pois_detected,
                changes_detected=job.changes_detected,
                change_summary=job.change_summary,
                error_message=job.error_message,
                next_scheduled_at=job.next_scheduled_at,
                duration_seconds=job.duration_seconds,
                is_overdue=job.is_overdue,
                can_retry=job.can_retry
            )
            for job in jobs
        ]

    except Exception as e:
        logger.error(
            "Failed to get pending POI refresh jobs",
            error=str(e),
            exc_info=True
        )
        raise HTTPException(
            status_code=500,
            detail=f"Failed to get pending jobs: {str(e)}"
        )


@router.post(
    "/trigger-scheduler",
    summary="Trigger scheduler immediately",
    description="Trigger an immediate check for pending jobs (bypasses schedule)"
)
async def trigger_scheduler():
    """Trigger POI refresh scheduler immediately"""
    try:
        scheduler = get_scheduler()

        if not scheduler.is_running:
            raise HTTPException(
                status_code=503,
                detail="POI refresh scheduler is not running"
            )

        result = await scheduler.trigger_immediate_check()

        logger.info(
            "POI refresh scheduler triggered via API",
            total_jobs=result["total_jobs"],
            successful=result["successful"],
            failed=result["failed"]
        )

        return result

    except HTTPException:
        raise
    except Exception as e:
        logger.error(
            "Failed to trigger POI refresh scheduler",
            error=str(e),
            exc_info=True
        )
        raise HTTPException(
            status_code=500,
            detail=f"Failed to trigger scheduler: {str(e)}"
        )


@router.get(
    "/scheduler/status",
    summary="Get scheduler status",
    description="Check if POI refresh scheduler is running"
)
async def get_scheduler_status():
    """Get POI refresh scheduler status"""
    try:
        scheduler = get_scheduler()

        return {
            "is_running": scheduler.is_running,
            "check_interval_seconds": scheduler.check_interval_seconds,
            "max_concurrent_jobs": scheduler.max_concurrent_jobs
        }

    except Exception as e:
        logger.error(
            "Failed to get scheduler status",
            error=str(e),
            exc_info=True
        )
        raise HTTPException(
            status_code=500,
            detail=f"Failed to get scheduler status: {str(e)}"
        )
