from datetime import datetime, timezone

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

from ..accounts.models import Account
from ..contacts.models import Contact
from ..leads.models import Lead
from ..opportunities.models import Opportunity
from .dto import ActivityCreate, ActivityUpdate
from .models import Activity

_ALLOWED_TYPES = {"call", "meeting", "task", "email", "note"}


def _validate_refs(db: Session, data: dict, tenant_id: int, company_id: int) -> None:
    """Valida las entidades relacionadas opcionales dentro del tenant/company."""
    def scope(model, _id):
        return (
            db.query(model.id)
            .filter(
                model.id == _id,
                model.tenant_id == tenant_id,
                model.company_id == company_id,
                model.deleted_at.is_(None),
            )
            .first()
        )

    checks = [
        ("account_id", Account, "La cuenta asociada no existe"),
        ("contact_id", Contact, "El contacto asociado no existe"),
        ("lead_id", Lead, "El prospecto asociado no existe"),
        ("opportunity_id", Opportunity, "La oportunidad asociada no existe"),
    ]
    for field, model, message in checks:
        value = data.get(field)
        if value is not None and not scope(model, value):
            raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=message)


def get_activities(
    db: Session,
    tenant_id: int,
    company_id: int,
    activity_type: str | None = None,
    activity_status: str | None = None,
    account_id: int | None = None,
    contact_id: int | None = None,
    lead_id: int | None = None,
    opportunity_id: int | None = None,
) -> list[Activity]:
    query = db.query(Activity).filter(
        Activity.tenant_id == tenant_id,
        Activity.company_id == company_id,
        Activity.deleted_at.is_(None),
    )
    if activity_type:
        query = query.filter(Activity.activity_type == activity_type)
    if activity_status:
        query = query.filter(Activity.status == activity_status)
    if account_id is not None:
        query = query.filter(Activity.account_id == account_id)
    if contact_id is not None:
        query = query.filter(Activity.contact_id == contact_id)
    if lead_id is not None:
        query = query.filter(Activity.lead_id == lead_id)
    if opportunity_id is not None:
        query = query.filter(Activity.opportunity_id == opportunity_id)
    return query.order_by(Activity.due_date.asc().nullslast(), Activity.created_at.desc()).all()


def get_activity(db: Session, activity_id: int, tenant_id: int, company_id: int) -> Activity:
    activity = (
        db.query(Activity)
        .filter(
            Activity.id == activity_id,
            Activity.tenant_id == tenant_id,
            Activity.company_id == company_id,
            Activity.deleted_at.is_(None),
        )
        .first()
    )
    if not activity:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Actividad no encontrada")
    return activity


def create_activity(db: Session, payload: ActivityCreate, tenant_id: int, company_id: int) -> Activity:
    if payload.activity_type not in _ALLOWED_TYPES:
        raise HTTPException(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
            detail="Tipo de actividad inválido",
        )
    data = payload.model_dump()
    _validate_refs(db, data, tenant_id, company_id)
    activity = Activity(**data, tenant_id=tenant_id, company_id=company_id)
    db.add(activity)
    db.commit()
    db.refresh(activity)
    return activity


def update_activity(
    db: Session, activity_id: int, payload: ActivityUpdate, tenant_id: int, company_id: int
) -> Activity:
    activity = get_activity(db, activity_id, tenant_id, company_id)
    data = payload.model_dump(exclude_unset=True)
    if data.get("activity_type") and data["activity_type"] not in _ALLOWED_TYPES:
        raise HTTPException(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
            detail="Tipo de actividad inválido",
        )
    _validate_refs(db, data, tenant_id, company_id)
    for field, value in data.items():
        setattr(activity, field, value)
    db.commit()
    db.refresh(activity)
    return activity


def complete_activity(db: Session, activity_id: int, tenant_id: int, company_id: int) -> Activity:
    activity = get_activity(db, activity_id, tenant_id, company_id)
    activity.status = "completed"
    activity.completed_at = datetime.now(timezone.utc)
    db.commit()
    db.refresh(activity)
    return activity


def delete_activity(db: Session, activity_id: int, tenant_id: int, company_id: int) -> None:
    activity = get_activity(db, activity_id, tenant_id, company_id)
    activity.deleted_at = datetime.now(timezone.utc)
    db.commit()
