from __future__ import annotations

import re
from datetime import datetime, date
from typing import Dict, Any, List, Optional

# ============================================================
# FUNÇÕES AUXILIARES (compatíveis com as usadas na certidão)
# ============================================================

def _clean_value(value: Optional[str]) -> Optional[str]:
    """Limpa espaços extras e pontuação final."""
    if not value:
        return None
    value = re.sub(r'\s+', ' ', value)
    value = re.sub(r'[.,;:]\s*$', '', value)
    return value.strip() or None

def _extract_by_label(text: str, label: str, next_labels: List[str] = None) -> Optional[str]:
    """
    Extrai o valor após um label até o próximo label (ou final do texto).
    next_labels: lista de strings que indicam o início do próximo campo.
    """
    label_esc = re.escape(label)
    pattern = rf'{label_esc}\s*[:\-]?\s*(.*?)'
    if next_labels:
        next_pattern = '|'.join(re.escape(nl) for nl in next_labels)
        pattern += rf'(?={next_pattern}|\Z)'
    else:
        pattern += r'(?=\n|\Z)'
    match = re.search(pattern, text, re.IGNORECASE | re.DOTALL)
    if match:
        return _clean_value(match.group(1))
    return None

def _parse_date_pt(value: str) -> Optional[date]:
    """Interpreta datas no formato '19 de Junho de 2018' ou '19/06/2018'."""
    if not value:
        return None
    value = value.strip().lower()
    # formato numérico
    for fmt in ("%d/%m/%Y", "%d-%m-%Y"):
        try:
            return datetime.strptime(value, fmt).date()
        except ValueError:
            pass
    # formato textual: "19 de junho de 2018"
    meses = {
        "janeiro": 1, "fevereiro": 2, "março": 3, "abril": 4,
        "maio": 5, "junho": 6, "julho": 7, "agosto": 8,
        "setembro": 9, "outubro": 10, "novembro": 11, "dezembro": 12,
    }
    match = re.search(r'(\d{1,2})\s+de\s+([a-zçãéêôíóú]+)\s+de\s+(\d{4})', value)
    if match:
        day = int(match.group(1))
        month_name = match.group(2).lower()
        year = int(match.group(3))
        month = meses.get(month_name)
        if month:
            try:
                return date(year, month, day)
            except ValueError:
                pass
    return None

def _normalize_company_name(name: str) -> str:
    """Remove sufixos comuns e normaliza maiúsculas."""
    if not name:
        return name
    # Remove sufixos como LDA, LIMITADA, SA, etc., mas preserva o nome principal
    name_upper = name.upper()
    for suffix in [" LDA", " LIMITADA", " SA", " S.A.", " & FILHOS"]:
        if name_upper.endswith(suffix):
            name = name[:-len(suffix)].strip()
    return name

# ============================================================
# ANALISADOR PRINCIPAL
# ============================================================

def analyze_alvara(
    *,
    text: str,
    extracted_entities: Dict[str, Any],
) -> Dict[str, Any]:
    """
    Analisa um Alvará Comercial.
    Retorna sinais estruturados e explicáveis.
    """
    alerts: List[str] = []
    confidence_points = 0
    max_confidence = 6

    # --------------------------------------------------------
    # 1️⃣ EMISSOR
    # --------------------------------------------------------
    # Verifica se já veio do extrator, senão procura no texto
    issuer = extracted_entities.get("issuer", "")
    if issuer:
        issuer_valid = bool(re.search(r"(república|governo|cidade de maputo)", issuer, re.IGNORECASE))
    else:
        issuer_valid = bool(re.search(r"(república de moçambique|governo|maputo)", text, re.IGNORECASE))
    if issuer_valid:
        confidence_points += 1
    else:
        alerts.append("(Neg) A entidade emissora do Alvará não corresponde a um órgão governamental reconhecido.")

    # --------------------------------------------------------
    # 2️⃣ NÚMERO DO ALVARÁ
    # --------------------------------------------------------
    alvara_number = extracted_entities.get("alvara_number")
    if not alvara_number:
        alvara_number = _extract_by_label(text, "Alvará Nº")
    if not alvara_number:
        # fallback com regex antiga
        match = re.search(r'alvar[aá]\s*(n[ºo]?)?\s*[:\-]?\s*([\w\/\-]+)', text, re.IGNORECASE)
        alvara_number = match.group(2).strip() if match else None
    if alvara_number:
        confidence_points += 1
    else:
        alerts.append("(Neg) O número do Alvará não foi identificado no documento.")

    # --------------------------------------------------------
    # 3️⃣ DECRETO
    # --------------------------------------------------------
    decreto_number = extracted_entities.get("decreto_number")
    if not decreto_number:
        decreto_number = _extract_by_label(text, "Decreto Nº")
    if not decreto_number:
        match = re.search(r'decreto\s*(n[ºo]?)?\s*[:\-]?\s*([\w\/\-]+)', text, re.IGNORECASE)
        decreto_number = match.group(2).strip() if match else None
    if decreto_number:
        confidence_points += 1
    else:
        alerts.append("(Neg) O Alvará não apresenta referência ao decreto legal que o fundamenta.")

    # --------------------------------------------------------
    # 4️⃣ TITULAR (NOME DA EMPRESA)
    # --------------------------------------------------------
    company_name = extracted_entities.get("company_name")
    if not company_name:
        company_name = _extract_by_label(text, "Titular")
    if company_name:
        company_name = _normalize_company_name(company_name)
        confidence_points += 1
    else:
        alerts.append("(Neg) O nome do titular não foi identificado de forma clara no Alvará.")

    # --------------------------------------------------------
    # 5️⃣ NUIT
    # --------------------------------------------------------
    nuit = extracted_entities.get("nuit")
    if not nuit:
        # Tenta extrair por label primeiro
        nuit = _extract_by_label(text, "NUT")  # no documento está "NUT"
        if not nuit:
            # fallback com regex
            match = re.search(r'\bNUIT\b\s*[:\-]?\s*(\d{9})', text, re.IGNORECASE)
            if not match:
                match = re.search(r'\bNUT\b\s*[:\-]?\s*(\d{9})', text, re.IGNORECASE)
            nuit = match.group(1) if match else None
    if nuit:
        confidence_points += 1
    else:
        alerts.append("(Neg) O NUIT não foi encontrado no Alvará.")

    # --------------------------------------------------------
    # 6️⃣ VALIDADE
    # --------------------------------------------------------
    validity_status = "UNKNOWN"
    validity_raw = extracted_entities.get("validity")
    if not validity_raw:
        validity_raw = _extract_by_label(text, "Validade")
    if validity_raw:
        validity_raw_upper = validity_raw.upper()
        if "INDETERMINADO" in validity_raw_upper:
            validity_status = "VALID"
            confidence_points += 1
        else:
            # tenta extrair uma data
            date_match = re.search(r'\b\d{1,2}[/\-]\d{1,2}[/\-]\d{4}\b', validity_raw)
            if date_match:
                parsed = _parse_date_pt(date_match.group())
                if parsed and parsed >= date.today():
                    validity_status = "VALID"
                    confidence_points += 1
                else:
                    validity_status = "EXPIRED"
                    alerts.append("(Neg) O Alvará apresentado encontra-se expirado.")
            else:
                alerts.append("(Info) A informação de validade do Alvará não pôde ser interpretada.")
    else:
        alerts.append("(Info) A informação de validade do Alvará não foi localizada.")

    # --------------------------------------------------------
    # CAMPOS ADICIONAIS (ENRIQUECIMENTO)
    # --------------------------------------------------------
    # Atividade principal
    atividade = _extract_by_label(text, "Actividade Principal")
    # Endereço
    endereco = _extract_by_label(text, "Endereço Estabelecimento")
    # Data de emissão
    data_emissao = None
    # No documento, a data aparece como "Maputo Cidade, 19 de Junho de 2018"
    date_match = re.search(r'Maputo Cidade,\s*(\d{1,2}\s+de\s+[a-zçãéêôíóú]+\s+de\s+\d{4})', text, re.IGNORECASE)
    if date_match:
        data_emissao = _parse_date_pt(date_match.group(1))
    # Código de verificação
    codigo_verif = None
    cod_match = re.search(r'\b(\d{20,})\b', text)  # exemplo: 004772018013670014151420
    if cod_match:
        codigo_verif = cod_match.group(1)

    # --------------------------------------------------------
    # CONFIANÇA FINAL
    # --------------------------------------------------------
    confidence = round(confidence_points / max_confidence, 2)
    analysis_status = "OK" if confidence >= 0.6 else "INCOMPLETE"

    return {
        "analysis_status": analysis_status,
        "issuer_valid": issuer_valid,
        "alvara_number": alvara_number,
        "decreto_number": decreto_number,
        "company_name": company_name,
        "nuit": nuit,
        "validity_status": validity_status,
        "validity_raw": validity_raw,
        "atividade_principal": atividade,
        "endereco": endereco,
        "data_emissao": data_emissao,
        "codigo_verificacao": codigo_verif,
        "alerts": alerts,
        "confidence": confidence,
    }