"""Transforma registros do Rubeus em linhas da planilha do funil.

Cada "registro" e um dicionario com (opcionalmente) duas chaves:
    {"oportunidade": {...}, "contato": {...}}

O mapeamento declarativo de colunas vem de config/mapeamento_campos.json.
"""
from __future__ import annotations

import json
from datetime import datetime
from pathlib import Path


def carregar_mapeamento(caminho: Path) -> list[dict]:
    dados = json.loads(Path(caminho).read_text(encoding="utf-8"))
    colunas = dados.get("colunas", [])
    if not colunas:
        raise ValueError(f"Mapeamento sem colunas em {caminho}")
    return colunas


def _por_caminho(obj: object, caminho: str):
    """Navega por um caminho com pontos (ex.: 'telefones.principal.telefone')."""
    atual = obj
    for parte in caminho.split("."):
        if isinstance(atual, dict):
            atual = atual.get(parte)
        else:
            return None
        if atual is None:
            return None
    return atual


def _primeiro_valor(obj: object, caminhos) -> object:
    if obj is None:
        return None
    if isinstance(caminhos, str):
        caminhos = [caminhos]
    for c in caminhos or []:
        valor = _por_caminho(obj, c)
        if valor not in (None, "", []):
            return valor
    return None


def _campo_personalizado(container: object, chave: str) -> object:
    """Le um campo personalizado, aceitando os dois formatos do Rubeus:

    - dict simples: {"chave": "valor"}
    - lista de objetos: [{"nome": ..., "coluna": "chave", "valor": "valor"}]
    """
    if not container or not chave:
        return None
    if isinstance(container, dict):
        if chave in container:
            return container[chave]
        return None
    if isinstance(container, list):
        for item in container:
            if not isinstance(item, dict):
                continue
            if item.get("coluna") == chave or item.get("nome") == chave:
                return item.get("valor")
    return None


def _fmt_datahora(valor: object) -> object:
    if valor is None:
        return None
    if isinstance(valor, dict):
        valor = valor.get("data") or valor.get("momento")
    if not isinstance(valor, str):
        return valor
    texto = valor.strip().replace("T", " ")
    for fmt in ("%Y-%m-%d %H:%M:%S", "%Y-%m-%d %H:%M", "%Y-%m-%d"):
        try:
            return datetime.strptime(texto, fmt).strftime("%d/%m/%Y %H:%M")
        except ValueError:
            continue
    return valor


def _fmt_data(valor: object) -> object:
    if not isinstance(valor, str):
        return valor
    for fmt in ("%Y-%m-%d", "%Y-%m-%d %H:%M:%S", "%Y-%m-%d %H:%M"):
        try:
            return datetime.strptime(valor.strip(), fmt).strftime("%d/%m/%Y")
        except ValueError:
            continue
    return valor


def _fmt_telefone(valor: object) -> object:
    if valor is None:
        return None
    return str(valor)


def _aplicar_tipo(valor: object, tipo: str) -> object:
    if valor is None:
        return None
    if tipo == "datahora":
        return _fmt_datahora(valor)
    if tipo == "data":
        return _fmt_data(valor)
    if tipo == "telefone":
        return _fmt_telefone(valor)
    return valor


def _resolver_fonte(registro: dict, fonte: str, spec: dict):
    oportunidade = registro.get("oportunidade") or {}
    contato = registro.get("contato") or {}
    if fonte == "oportunidade":
        return _primeiro_valor(oportunidade, spec.get("caminho"))
    if fonte == "contato":
        return _primeiro_valor(contato, spec.get("caminho"))
    if fonte == "oportunidade_cp":
        return _campo_personalizado(oportunidade.get("camposPersonalizados"), spec.get("chave"))
    if fonte == "contato_cp":
        return _campo_personalizado(contato.get("camposPersonalizados"), spec.get("chave"))
    if fonte == "fixo":
        return spec.get("valor")
    return None


def valor_coluna(registro: dict, spec: dict):
    valor = _resolver_fonte(registro, spec.get("fonte", ""), spec)
    if valor in (None, "", []) and spec.get("fonte_alt"):
        valor = _resolver_fonte(registro, spec["fonte_alt"], spec)
    valor = _aplicar_tipo(valor, spec.get("tipo", "texto"))
    if valor in (None, "", []):
        return spec.get("default")
    return valor


def montar_linha(registro: dict, colunas: list[dict]) -> list:
    return [valor_coluna(registro, spec) for spec in colunas]
