from typing import Any

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session

from core.database import get_core_db
from core.security import get_current_user, resolve_tenant_id_required

from .models import TaskRun, TaskStatus
from .schemas import TaskCatalogsResponse, TaskRunDetail, TaskRunListItem, TaskRunsResponse, TaskSyncRequest
from .service import TaskTrackerService

router = APIRouter()


def _map_row(row: TaskRun) -> TaskRunListItem:
    pct = row.progress_percent
    if row.status == TaskStatus.COMPLETED.value and (pct is None or pct == 0):
        pct = 100.0
    return TaskRunListItem(
        task_id=row.task_id,
        task_name=row.task_name,
        task_group=row.task_group,
        task_origin=row.task_origin,
        status=row.status,
        celery_state_raw=row.celery_state_raw,
        progress={
            "current": row.progress_current,
            "total": row.progress_total,
            "percent": pct,
            "message": row.progress_message,
        },
        retries=row.retries,
        error=(
            {"type": row.exception_type, "message": row.exception_message}
            if row.exception_type or row.exception_message
            else None
        ),
        tenant_id=row.tenant_id,
        requested_by_user=row.requested_by_user,
        started_at=row.started_at,
        finished_at=row.finished_at,
        created_at=row.created_at,
        updated_at=row.updated_at,
    )


@router.get("/tasks", response_model=TaskRunsResponse)
def list_tasks(
    page: int = Query(1, ge=1),
    page_size: int = Query(50, ge=1, le=200),
    status: list[str] | None = Query(None),
    task_group: list[str] | None = Query(None),
    task_name: list[str] | None = Query(None),
    company_id: int | None = Query(None),
    search: str | None = Query(None),
    sync_active: bool = Query(False),
    current_user: dict[str, Any] = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    tenant_id = resolve_tenant_id_required(current_user)

    tracker = TaskTrackerService(db)
    if sync_active:
        tracker.sync_active_tasks(tenant_id=tenant_id)

    rows, total = tracker.list_tasks(
        tenant_id=tenant_id,
        page=page,
        page_size=page_size,
        status=status,
        task_group=task_group,
        task_name=task_name,
        company_id=company_id,
        search=search,
    )
    items = [_map_row(row) for row in rows]
    return TaskRunsResponse(
        items=items,
        total=total,
        page=page,
        page_size=page_size,
        has_next=(page * page_size) < total,
    )


@router.get("/tasks/{task_id}", response_model=TaskRunDetail)
def get_task_detail(
    task_id: str,
    sync: bool = Query(True),
    current_user: dict[str, Any] = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    tenant_id = resolve_tenant_id_required(current_user)

    query = db.query(TaskRun).filter(TaskRun.task_id == task_id)
    if tenant_id is not None:
        query = query.filter(TaskRun.tenant_id == tenant_id)
    row = query.first()
    if not row:
        raise HTTPException(status_code=404, detail="Task not found")

    tracker = TaskTrackerService(db)
    if sync:
        row = tracker.sync_task(row)

    item = _map_row(row)
    return TaskRunDetail(
        **item.model_dump(),
        traceback_excerpt=row.traceback_excerpt,
        result_summary=row.result_summary,
        meta_payload=row.meta_payload,
    )


@router.post("/tasks/sync")
def sync_tasks(
    body: TaskSyncRequest,
    current_user: dict[str, Any] = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    tenant_id = resolve_tenant_id_required(current_user)
    tracker = TaskTrackerService(db)
    updated = tracker.sync_active_tasks(tenant_id=tenant_id, task_ids=body.task_ids)
    return {"updated": updated}


@router.get("/tasks/catalogs", response_model=TaskCatalogsResponse)
def get_catalogs(
    current_user: dict[str, Any] = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    tenant_id = resolve_tenant_id_required(current_user)

    groups_q = db.query(TaskRun.task_group)
    names_q = db.query(TaskRun.task_name)
    statuses_q = db.query(TaskRun.status)
    if tenant_id is not None:
        groups_q = groups_q.filter(TaskRun.tenant_id == tenant_id)
        names_q = names_q.filter(TaskRun.tenant_id == tenant_id)
        statuses_q = statuses_q.filter(TaskRun.tenant_id == tenant_id)
    groups = groups_q.distinct().order_by(TaskRun.task_group).all()
    names = names_q.distinct().order_by(TaskRun.task_name).all()
    statuses = statuses_q.distinct().order_by(TaskRun.status).all()
    return TaskCatalogsResponse(
        task_groups=[g[0] for g in groups if g[0]],
        task_names=[n[0] for n in names if n[0]],
        statuses=[s[0] for s in statuses if s[0]],
    )
