from datetime import datetime, timezone

from fastapi import HTTPException, status
from sqlalchemy.orm import Session

from ..accounts.models import Account
from ..suppliers.models import Supplier
from .dto import DocumentCreate, DocumentUpdate
from .models import Document


def _validate_owner(db: Session, account_id: int | None, supplier_id: int | None, tenant_id: int, company_id: int) -> None:
    """Un documento debe pertenecer a exactamente un cliente o proveedor existente."""
    if (account_id is None) == (supplier_id is None):
        raise HTTPException(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
            detail="El documento debe asociarse a un cliente O a un proveedor",
        )
    model, _id, msg = (
        (Account, account_id, "El cliente asociado no existe")
        if account_id is not None
        else (Supplier, supplier_id, "El proveedor asociado no existe")
    )
    exists = (
        db.query(model.id)
        .filter(
            model.id == _id,
            model.tenant_id == tenant_id,
            model.company_id == company_id,
            model.deleted_at.is_(None),
        )
        .first()
    )
    if not exists:
        raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=msg)


def get_documents(
    db: Session,
    tenant_id: int,
    company_id: int,
    account_id: int | None = None,
    supplier_id: int | None = None,
) -> list[Document]:
    query = db.query(Document).filter(
        Document.tenant_id == tenant_id,
        Document.company_id == company_id,
        Document.deleted_at.is_(None),
    )
    if account_id is not None:
        query = query.filter(Document.account_id == account_id)
    if supplier_id is not None:
        query = query.filter(Document.supplier_id == supplier_id)
    return query.order_by(Document.created_at.desc()).all()


def get_document(db: Session, document_id: int, tenant_id: int, company_id: int) -> Document:
    document = (
        db.query(Document)
        .filter(
            Document.id == document_id,
            Document.tenant_id == tenant_id,
            Document.company_id == company_id,
            Document.deleted_at.is_(None),
        )
        .first()
    )
    if not document:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Documento no encontrado")
    return document


def create_document(
    db: Session, payload: DocumentCreate, tenant_id: int, company_id: int, user_id: str | None = None
) -> Document:
    _validate_owner(db, payload.account_id, payload.supplier_id, tenant_id, company_id)
    document = Document(
        **payload.model_dump(), tenant_id=tenant_id, company_id=company_id, uploaded_by=user_id
    )
    db.add(document)
    db.commit()
    db.refresh(document)
    return document


def update_document(
    db: Session, document_id: int, payload: DocumentUpdate, tenant_id: int, company_id: int
) -> Document:
    document = get_document(db, document_id, tenant_id, company_id)
    for field, value in payload.model_dump(exclude_unset=True).items():
        setattr(document, field, value)
    db.commit()
    db.refresh(document)
    return document


def delete_document(db: Session, document_id: int, tenant_id: int, company_id: int) -> None:
    document = get_document(db, document_id, tenant_id, company_id)
    document.deleted_at = datetime.now(timezone.utc)
    db.commit()
