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 AddressCreate, AddressUpdate
from .models import Address


def _validate_owner(db: Session, account_id: int | None, supplier_id: int | None, tenant_id: int, company_id: int) -> None:
    """Una dirección 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="La dirección 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_addresses(
    db: Session,
    tenant_id: int,
    company_id: int,
    account_id: int | None = None,
    supplier_id: int | None = None,
) -> list[Address]:
    query = db.query(Address).filter(
        Address.tenant_id == tenant_id,
        Address.company_id == company_id,
        Address.deleted_at.is_(None),
    )
    if account_id is not None:
        query = query.filter(Address.account_id == account_id)
    if supplier_id is not None:
        query = query.filter(Address.supplier_id == supplier_id)
    return query.order_by(Address.is_primary.desc(), Address.id.asc()).all()


def get_address(db: Session, address_id: int, tenant_id: int, company_id: int) -> Address:
    address = (
        db.query(Address)
        .filter(
            Address.id == address_id,
            Address.tenant_id == tenant_id,
            Address.company_id == company_id,
            Address.deleted_at.is_(None),
        )
        .first()
    )
    if not address:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Dirección no encontrada")
    return address


def create_address(db: Session, payload: AddressCreate, tenant_id: int, company_id: int) -> Address:
    _validate_owner(db, payload.account_id, payload.supplier_id, tenant_id, company_id)
    address = Address(**payload.model_dump(), tenant_id=tenant_id, company_id=company_id)
    db.add(address)
    db.commit()
    db.refresh(address)
    return address


def update_address(
    db: Session, address_id: int, payload: AddressUpdate, tenant_id: int, company_id: int
) -> Address:
    address = get_address(db, address_id, tenant_id, company_id)
    for field, value in payload.model_dump(exclude_unset=True).items():
        setattr(address, field, value)
    db.commit()
    db.refresh(address)
    return address


def delete_address(db: Session, address_id: int, tenant_id: int, company_id: int) -> None:
    address = get_address(db, address_id, tenant_id, company_id)
    address.deleted_at = datetime.now(timezone.utc)
    db.commit()
