from datetime import datetime, timezone

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

from api.v1.modules.fin.catalogs.models import CfdiUse, TaxRegime

from .dto import AccountCreate, AccountUpdate
from .models import Account


def _validate_sat_refs(db: Session, data: dict) -> None:
    """Verifica las claves del SAT del receptor antes de guardar la cuenta."""
    for field, model, msg in [
        ("tax_regime_id", TaxRegime, "El régimen fiscal indicado no existe en el catálogo del SAT"),
        ("cfdi_use_id", CfdiUse, "El uso de CFDI indicado no existe en el catálogo del SAT"),
    ]:
        value = data.get(field)
        if field in data and value is not None:
            if db.query(model.id).filter(model.id == value).first() is None:
                raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=msg)


def get_accounts(
    db: Session,
    tenant_id: int,
    company_id: int,
    search: str | None = None,
    account_status: str | None = None,
    record_type: str | None = None,
) -> list[Account]:
    query = db.query(Account).filter(
        Account.tenant_id == tenant_id,
        Account.company_id == company_id,
        Account.deleted_at.is_(None),
    )
    if search:
        pattern = f"%{search}%"
        query = query.filter(
            Account.name.ilike(pattern)
            | Account.trade_name.ilike(pattern)
            | Account.rfc.ilike(pattern)
        )
    if account_status:
        query = query.filter(Account.status == account_status)
    if record_type:
        query = query.filter(Account.record_type == record_type)
    return query.order_by(Account.name.asc()).all()


def get_account(db: Session, account_id: int, tenant_id: int, company_id: int) -> Account:
    account = (
        db.query(Account)
        .filter(
            Account.id == account_id,
            Account.tenant_id == tenant_id,
            Account.company_id == company_id,
            Account.deleted_at.is_(None),
        )
        .first()
    )
    if not account:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Cliente no encontrado")
    return account


def create_account(
    db: Session, payload: AccountCreate, tenant_id: int, company_id: int, user_id: str | None = None
) -> Account:
    data = payload.model_dump()
    _validate_sat_refs(db, data)
    account = Account(
        **data,
        tenant_id=tenant_id,
        company_id=company_id,
        created_by=user_id,
        updated_by=user_id,
    )
    db.add(account)
    db.commit()
    db.refresh(account)
    return account


def update_account(
    db: Session,
    account_id: int,
    payload: AccountUpdate,
    tenant_id: int,
    company_id: int,
    user_id: str | None = None,
) -> Account:
    account = get_account(db, account_id, tenant_id, company_id)
    data = payload.model_dump(exclude_unset=True)
    _validate_sat_refs(db, data)
    for field, value in data.items():
        setattr(account, field, value)
    account.updated_by = user_id
    db.commit()
    db.refresh(account)
    return account


def delete_account(db: Session, account_id: int, tenant_id: int, company_id: int) -> None:
    account = get_account(db, account_id, tenant_id, company_id)
    # Soft delete: conserva el histórico comercial del cliente
    account.deleted_at = datetime.now(timezone.utc)
    db.commit()
