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 ContactCreate, ContactUpdate
from .models import Contact


def _validate_parent(db: Session, data: dict, tenant_id: int, company_id: int) -> None:
    """Verifica que el cliente/proveedor referenciado exista en el tenant/company."""
    account_id = data.get("account_id")
    if account_id is not None:
        exists = (
            db.query(Account.id)
            .filter(
                Account.id == account_id,
                Account.tenant_id == tenant_id,
                Account.company_id == company_id,
                Account.deleted_at.is_(None),
            )
            .first()
        )
        if not exists:
            raise HTTPException(
                status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
                detail="El cliente asociado no existe",
            )
    supplier_id = data.get("supplier_id")
    if supplier_id is not None:
        exists = (
            db.query(Supplier.id)
            .filter(
                Supplier.id == supplier_id,
                Supplier.tenant_id == tenant_id,
                Supplier.company_id == company_id,
                Supplier.deleted_at.is_(None),
            )
            .first()
        )
        if not exists:
            raise HTTPException(
                status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
                detail="El proveedor asociado no existe",
            )


def get_contacts(
    db: Session,
    tenant_id: int,
    company_id: int,
    search: str | None = None,
    account_id: int | None = None,
    supplier_id: int | None = None,
) -> list[Contact]:
    query = db.query(Contact).filter(
        Contact.tenant_id == tenant_id,
        Contact.company_id == company_id,
        Contact.deleted_at.is_(None),
    )
    if account_id is not None:
        query = query.filter(Contact.account_id == account_id)
    if supplier_id is not None:
        query = query.filter(Contact.supplier_id == supplier_id)
    if search:
        pattern = f"%{search}%"
        query = query.filter(
            Contact.first_name.ilike(pattern)
            | Contact.last_name.ilike(pattern)
            | Contact.email.ilike(pattern)
        )
    return query.order_by(Contact.first_name.asc()).all()


def get_contact(db: Session, contact_id: int, tenant_id: int, company_id: int) -> Contact:
    contact = (
        db.query(Contact)
        .filter(
            Contact.id == contact_id,
            Contact.tenant_id == tenant_id,
            Contact.company_id == company_id,
            Contact.deleted_at.is_(None),
        )
        .first()
    )
    if not contact:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Contacto no encontrado")
    return contact


def create_contact(db: Session, payload: ContactCreate, tenant_id: int, company_id: int) -> Contact:
    data = payload.model_dump()
    _validate_parent(db, data, tenant_id, company_id)
    contact = Contact(**data, tenant_id=tenant_id, company_id=company_id)
    db.add(contact)
    db.commit()
    db.refresh(contact)
    return contact


def update_contact(
    db: Session, contact_id: int, payload: ContactUpdate, tenant_id: int, company_id: int
) -> Contact:
    contact = get_contact(db, contact_id, tenant_id, company_id)
    data = payload.model_dump(exclude_unset=True)
    _validate_parent(db, data, tenant_id, company_id)
    for field, value in data.items():
        setattr(contact, field, value)
    db.commit()
    db.refresh(contact)
    return contact


def delete_contact(db: Session, contact_id: int, tenant_id: int, company_id: int) -> None:
    contact = get_contact(db, contact_id, tenant_id, company_id)
    contact.deleted_at = datetime.now(timezone.utc)
    db.commit()
