from __future__ import annotations

from datetime import datetime
from decimal import Decimal
from typing import List, Optional, Dict, Any

from pydantic import BaseModel, EmailStr, Field


class ConfiguracionVU(BaseModel):
    """
    Configuración de Ventanilla Única / VUCEM para generación de COVE.

    Nota: estos campos se pueden poblar desde CustomsBrokerVU (web_service_user,
    web_service_access_key, fiel_access_key, query_tax_id, etc.) o desde el
    propio request de la API pública, según el flujo que se implemente.
    """

    rfc_usuario_vu: str = Field(..., max_length=30)
    # Clave encriptada/token del webservice; puede ser larga (base64)
    clave_webservice: str = Field(..., max_length=512)
    archivo_cer_base64: str
    archivo_key_base64: str
    clave_fiel: str = Field(..., max_length=100)


class PersonaCove(BaseModel):
    tipo_identificador: str = Field(..., max_length=10)
    identificacion: str = Field(..., max_length=30)
    apellido_paterno: str = Field(default="", max_length=80)
    apellido_materno: str = Field(default="", max_length=80)
    nombre: str = Field(default="", max_length=80)
    calle: str = Field(default="", max_length=120)
    numero_exterior: str = Field(default="", max_length=20)
    numero_interior: str = Field(default="", max_length=20)
    colonia: str = Field(default="", max_length=120)
    localidad: str = Field(default="", max_length=120)
    municipio: str = Field(default="", max_length=120)
    entidad_federativa: str = Field(default="", max_length=120)
    pais: str = Field(..., max_length=3, description="País en formato ISO o catálogo VU")
    codigo_postal: str = Field(default="", max_length=15)


class DescripcionEspecifica(BaseModel):
    marca: str = Field(default="", max_length=80)
    modelo: str = Field(default="", max_length=80)
    submodelo: str = Field(default="", max_length=80)
    numero_serie: str = Field(default="", max_length=80)


class MercanciaCove(BaseModel):
    descripcion_generica: str = Field(..., max_length=500)
    clave_unidad_medida: str = Field(..., max_length=10)
    tipo_moneda: str = Field(..., max_length=5)
    cantidad: Decimal = Field(..., gt=0)
    valor_unitario: Decimal = Field(..., ge=0)
    valor_total: Decimal = Field(..., ge=0)
    valor_dolares: Decimal = Field(default=Decimal("0"), ge=0)
    descripcion_especifica: List[DescripcionEspecifica] = Field(default_factory=list)


class FacturaCoveRequest(BaseModel):
    """
    Payload completo para generación de COVE.

    Este modelo replica el contrato del servicio externo de COVE que se
    mostró en la documentación compartida por el usuario.
    """

    configuracion_vu: ConfiguracionVU
    rfc_consulta: str = Field(..., max_length=30)
    tipo_figura: str = Field(..., max_length=10)
    numero_factura: str = Field(..., max_length=50)
    tipo_operacion: str = Field(..., max_length=10)
    patente_aduanal: str = Field(..., max_length=10)
    fecha_expedicion: datetime
    observaciones: Optional[str] = Field(None, max_length=500)
    correo_electronico: Optional[EmailStr] = None
    tiene_subdivision: bool = False
    certificado_origen: bool = False
    numero_exportador_autorizado: Optional[str] = Field(None, max_length=50)
    emisor: PersonaCove
    destinatario: PersonaCove
    mercancias: List[MercanciaCove] = Field(default_factory=list, min_length=1)


class FacturaCoveResponse(BaseModel):
    """
    Respuesta base del endpoint público de generación de COVE.
    Para el flujo asíncrono interno, solo usamos task_id/status/message.
    """

    task_id: Optional[str] = None
    status: str
    message: Optional[str] = None


class GenerateCoveFromInvoiceRequest(BaseModel):
    """
    Request minimalista desde la vista de facturas.

    Solo necesita el company_id porque el invoice_id viene en la URL y el
    tenant_id se resuelve desde el token.
    """

    company_id: int
    force_regen: Optional[bool] = False
    recipient_email: Optional[EmailStr] = None


class GenerateCoveResult(BaseModel):
    """
    Resultado estándar que produce la tarea Celery factura_cove_generate.
    """

    status: str
    message: Optional[str] = None
    invoice_id: Optional[int] = None
    cove_number: Optional[str] = None
    vucem_operation_num: Optional[str] = None
    # ID de tarea devuelto por el servicio externo de COVE (si aplica)
    external_task_id: Optional[str] = None
    # Respuesta cruda devuelta por el servicio externo (POST generar-factura-cove)
    external_response: Optional[Dict[str, Any]] = None
    errors: Optional[list[dict]] = None


class CoveEligibilityIssue(BaseModel):
    field: str
    message: str


class CoveEligibilityResponse(BaseModel):
    can_generate: bool
    reasons: list[CoveEligibilityIssue] = Field(default_factory=list)

