"""
Rutas de importación CSV para Agentes Aduanales.
Mismo flujo que a76.imports: upload → scan → status (polling) → commit.
"""
import json
import logging
import os
from uuid import uuid4

from fastapi import APIRouter, File, HTTPException, Query, UploadFile, Depends
from sqlalchemy.orm import Session
from typing import Dict, Any

from core.celery_app import celery_app
from core.database import get_core_db
from core.security import get_current_user, validate_access_to_resource
from api.v1.modules.core.tasks_tracking import track_and_dispatch

from ..common.track_commit_dispatch import dispatch_tracked_layouts_csv_commit
from ..common.responses import normalize_commit_status_payload
from .schemas import ImportJobResponse
from .tasks import (
    scan_file,
    insert_valid_rows,
    JOB_TYPE,
    CB_IMPORT_META_PREFIX,
    CB_IMPORT_REDIS_TTL,
)
from ..common import storage as common_storage
from ..common.error_csv import download_scan_errors_csv_stream

router = APIRouter()
logger = logging.getLogger(__name__)


def _get_redis():
    import redis
    url = os.getenv("VALKEY_URL", os.getenv("REDIS_URL", "redis://valkey:6379/0"))
    return redis.Redis.from_url(url, decode_responses=False)


@router.post("/upload", response_model=ImportJobResponse)
async def upload_import_file(
    file: UploadFile = File(...),
    company_id: int = Query(..., description="Company ID"),
    db: Session = Depends(get_core_db),
    current_user: Dict[str, Any] = Depends(get_current_user),
):
    """
    Fase 1: Subir CSV, guardar en Redis, encolar tarea de escaneo.
    """
    try:
        tenant_id = validate_access_to_resource(db, company_id, current_user, ["csv_upload.process"])
    except Exception as e:
        logger.error(f"CB import: access validation failed: {e}")
        raise HTTPException(status_code=403, detail="Invalid company access or missing permissions")

    if not file.filename or not file.filename.lower().endswith(".csv"):
        raise HTTPException(status_code=400, detail="Solo se permiten archivos .csv")

    job_id = str(uuid4())
    contents = await file.read()

    meta_data = {
        "tenant_id": tenant_id,
        "company_id": company_id,
        "user_id": current_user.get("id"),
        "template_id": "customs_brokers",
    }

    try:
        common_storage.store_import_file(
            JOB_TYPE,
            job_id,
            contents,
            meta_data,
            tenant_id=int(tenant_id),
            company_id=company_id,
            ttl=CB_IMPORT_REDIS_TTL,
            log_label="CB import",
        )
    except common_storage.ImportStoreError as e:
        logger.error(f"CB import: store error: {e}")
        raise HTTPException(status_code=500, detail="No se pudo encolar el archivo.")
    except Exception as e:
        logger.error(f"CB import: Redis store error: {e}")
        raise HTTPException(status_code=500, detail="No se pudo encolar el archivo.")

    track_and_dispatch(
        db=db,
        task=scan_file,
        tenant_id=int(tenant_id),
        company_id=company_id,
        requested_by_user=current_user.get("preferred_username")
        or current_user.get("email")
        or current_user.get("sub"),
        task_name="customs_brokers_scan_file",
        task_group="layouts_csv",
        task_origin="a76/layouts_csv/customs_brokers/upload",
        args=[job_id],
        task_id=job_id,
    )

    return ImportJobResponse(
        job_id=job_id,
        status="queued",
        message="Archivo subido. Escaneo iniciado.",
    )


@router.get("/{job_id}/status")
async def get_import_status(job_id: str):
    """
    Polling: estado del escaneo o del commit.
    """
    task_result = celery_app.AsyncResult(job_id)

    if task_result.state == "PENDING":
        return {"status": "processing", "progress": 0}
    if task_result.state == "PROGRESS":
        info = (task_result.info or {})
        return {
            "status": "processing",
            "progress": info.get("current", 0),
            "total": info.get("total", 0),
        }
    if task_result.state == "SUCCESS":
        result = task_result.result
        if isinstance(result, dict) and "status" in result:
            return normalize_commit_status_payload(result)
        return {"status": "finished", "result": result}

    # A veces Celery tiene el result disponible pero state aún no es SUCCESS; si el result es éxito, devolverlo
    result = getattr(task_result, "result", None)
    if isinstance(result, dict) and result.get("status") in ("finished", "warning"):
        return normalize_commit_status_payload(result)

    logger.warning("CB import task %s failed: state=%s", job_id, task_result.state)
    err_msg = None
    tb = getattr(task_result, "traceback", None)
    if tb and isinstance(tb, str):
        lines = [l.strip() for l in tb.strip().split("\n") if l.strip()]
        if lines:
            err_msg = lines[-1]
    if not err_msg:
        try:
            exc = task_result.get(propagate=False)
            if exc is not None:
                err_msg = str(exc)
        except Exception:
            pass
    if not err_msg and result is not None:
        if not isinstance(result, dict):
            err_msg = str(result)
        elif result.get("error") or result.get("message"):
            err_msg = result.get("error") or result.get("message")
    return {"status": "failed", "error": err_msg or "Task failed"}


@router.post("/{job_id}/commit")
async def commit_import_job(
    job_id: str,
    db: Session = Depends(get_core_db),
    current_user: Dict[str, Any] = Depends(get_current_user),
):
    """
    Fase 2: Usuario confirma; se encola la inserción de filas válidas.
    """
    r = _get_redis()
    commit_id = dispatch_tracked_layouts_csv_commit(
        db=db,
        current_user=current_user,
        redis_client=r,
        layout_job_id=job_id,
        meta_redis_key=f"{CB_IMPORT_META_PREFIX}{job_id}",
        celery_task=insert_valid_rows,
        task_name="customs_brokers_insert_valid_rows",
        task_origin="a76/layouts_csv/customs_brokers/commit",
        args=[job_id],
        required_permissions=["csv_upload.process"],
    )
    return {
        "status": "committing",
        "message": "Inserción iniciada.",
        "commit_job_id": commit_id,
    }


@router.get("/{job_id}/errors/scan-csv")
async def download_scan_errors_csv(job_id: str):
    return download_scan_errors_csv_stream("cb", job_id)
