"""Subida de archivos a MinIO/S3 para documentos del CRM y Operaciones.

Flujo: el frontend sube el archivo aquí, recibe ``file_key`` (permanente) y lo
guarda en el documento (crm.documents / ops.shipment_documents). Para abrirlo se
pide una URL firmada fresca en ``/uploads/url`` (las presignadas expiran).
"""
import re
import uuid

from fastapi import APIRouter, Depends, File, HTTPException, Query, Response, UploadFile, status

from core.security import get_current_user
from core.storage_s3 import get_object_bytes, presigned_get_url, put_object_bytes

router = APIRouter()

MAX_UPLOAD_BYTES = 25 * 1024 * 1024  # 25 MB
_SAFE_NAME = re.compile(r"[^A-Za-z0-9._-]+")


def _safe_filename(name: str | None) -> str:
    base = (name or "archivo").strip().replace(" ", "_")
    base = _SAFE_NAME.sub("", base) or "archivo"
    return base[:120]


@router.post("/uploads")
async def upload_file(
    file: UploadFile = File(...),
    company_id: int = Query(..., description="Company ID"),
    current_user: dict = Depends(get_current_user),
):
    tenant_id = current_user["tenant_id"]
    content = await file.read()
    if len(content) > MAX_UPLOAD_BYTES:
        raise HTTPException(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
            detail="El archivo excede el tamaño máximo permitido (25 MB)",
        )
    filename = _safe_filename(file.filename)
    key = f"tenants/{tenant_id}/companies/{company_id}/crm-docs/{uuid.uuid4().hex}/{filename}"
    put_object_bytes(key, content, content_type=file.content_type or "application/octet-stream")
    return {
        "file_key": key,
        "file_url": presigned_get_url(key),
        "name": file.filename,
        "content_type": file.content_type,
        "size_bytes": len(content),
    }


@router.get("/uploads/url")
def get_upload_url(
    key: str = Query(..., description="Object key del archivo en el almacén"),
    company_id: int = Query(..., description="Company ID"),
    current_user: dict = Depends(get_current_user),
):
    tenant_id = current_user["tenant_id"]
    # Un archivo solo puede consultarse dentro de su propio tenant/company (aislamiento).
    prefix = f"tenants/{tenant_id}/companies/{company_id}/"
    if not key.startswith(prefix):
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Archivo fuera de tu alcance")
    return {"url": presigned_get_url(key)}


@router.get("/uploads/download")
def download_file(
    key: str = Query(..., description="Object key del archivo en el almacén"),
    company_id: int = Query(..., description="Company ID"),
    current_user: dict = Depends(get_current_user),
):
    """Transmite el archivo por el backend (sin exponer MinIO al navegador).

    Evita el bug de la URL prefirmada que apunta al host interno ``minio:9000``.
    """
    tenant_id = current_user["tenant_id"]
    prefix = f"tenants/{tenant_id}/companies/{company_id}/"
    if not key.startswith(prefix):
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Archivo fuera de tu alcance")
    try:
        data = get_object_bytes(key)
    except Exception:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Archivo no encontrado")
    filename = key.rsplit("/", 1)[-1]
    return Response(
        content=data,
        media_type="application/octet-stream",
        headers={"Content-Disposition": f'inline; filename="{filename}"'},
    )
