"""
Rutas de importación CSV para Transportistas.
Flujo: upload → scan → status (polling) → commit.
"""
import base64
import json
import logging
import os
import threading
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.paths import layout_path
from core.security import get_current_user, validate_access_to_resource
from api.v1.modules.core.tasks_tracking import track_and_dispatch

from .schemas import ImportJobResponse
from .tasks import (
    scan_file,
    run_scan_sync,
    run_commit_sync,
    TRP_IMPORT_FILE_PREFIX,
    TRP_IMPORT_META_PREFIX,
    TRP_IMPORT_STATUS_PREFIX,
    TRP_IMPORT_REDIS_TTL,
)
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"),
    actualizar: bool = Query(False, description="Modo Agregar/Actualizar (ACT); si True, validación parcial para claves existentes"),
    db: Session = Depends(get_core_db),
    current_user: Dict[str, Any] = Depends(get_current_user),
):
    try:
        tenant_id = validate_access_to_resource(db, company_id, current_user)
    except Exception as e:
        logger.error("Transportistas import: access validation failed: %s", e)
        raise HTTPException(status_code=403, detail="Invalid company access")

    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": "transporters",
        "actualizar": actualizar,
    }

    try:
        r = _get_redis()
        r.set(
            f"{TRP_IMPORT_FILE_PREFIX}{job_id}",
            base64.b64encode(contents),
            ex=TRP_IMPORT_REDIS_TTL,
        )
        r.set(
            f"{TRP_IMPORT_META_PREFIX}{job_id}",
            json.dumps(meta_data).encode("utf-8"),
            ex=TRP_IMPORT_REDIS_TTL,
        )
    except Exception as e:
        logger.error("Transportistas import: Redis store error: %s", e)
        raise HTTPException(status_code=500, detail="No se pudo encolar el archivo.")

    try:
        upload_dir = layout_path("imports", "temp")
        os.makedirs(upload_dir, exist_ok=True)
        with open(os.path.join(upload_dir, f"trp_{job_id}.csv"), "wb") as f:
            f.write(contents)
        with open(os.path.join(upload_dir, f"trp_{job_id}.meta.json"), "w") as f:
            json.dump(meta_data, f)
    except Exception as e:
        logger.warning("Transportistas import: local file save failed: %s", e)

    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="transportistas_scan_file",
        task_group="layouts_csv",
        task_origin="a76/layouts_csv/transportistas/upload",
        args=[job_id],
        task_id=job_id,
    )

    def run_scan_background():
        try:
            run_scan_sync(job_id)
        except Exception as e:
            logger.exception("Transportistas import: background scan failed: %s", e)

    threading.Thread(target=run_scan_background, daemon=True).start()

    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):
    try:
        r = _get_redis()
        raw = r.get(f"{TRP_IMPORT_STATUS_PREFIX}{job_id}")
        if raw:
            data = json.loads(raw.decode("utf-8"))
            return data
    except Exception as e:
        logger.debug("Transportistas import: could not read status from Redis: %s", e)

    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 result
        return {"status": "finished", "result": result}

    result = getattr(task_result, "result", None)
    if isinstance(result, dict) and result.get("status") in ("finished", "warning"):
        return result

    logger.warning("Transportistas 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):
    try:
        r = _get_redis()
        r.set(
            f"{TRP_IMPORT_STATUS_PREFIX}{job_id}",
            json.dumps({"status": "processing", "message": "Insertando..."}).encode("utf-8"),
            ex=TRP_IMPORT_REDIS_TTL,
        )
    except Exception as e:
        logger.debug("Transportistas import: could not write processing status: %s", e)

    def run_commit_background():
        try:
            run_commit_sync(job_id)
        except Exception as e:
            logger.exception("Transportistas import: background commit failed: %s", e)

    threading.Thread(target=run_commit_background, daemon=True).start()

    return {
        "status": "committing",
        "message": "Inserción iniciada.",
        "commit_job_id": job_id,
    }


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