#!/usr/bin/env python3
"""
gerar_diagrama.py — gera diagrama .excalidraw a partir de template + dados.

Uso:
    python3 gerar_diagrama.py --template funil --dados dados.json --saida saida.excalidraw
    python3 gerar_diagrama.py --template matriz_2x2 --paleta imperatriz --saida ~/saida.excalidraw --obsidian

Templates: funil, matriz_2x2, jornada, hub_spoke, timeline, mapa_mental
Paletas: imperatriz, mckinsey, dark_premium, notion_minimal
"""

import argparse
import json
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent))

from helpers.excalidraw import (  # noqa: E402
    card_premium,
    cena_excalidraw,
    cena_obsidian_md,
    conector_inteligente,
    container_secao,
    elipse,
    envelopa_em_frame,
    frame,
    highlighter,
    linha,
    post_it,
    retangulo,
    salvar,
    seta,
    texto,
)
from helpers.paleta import (  # noqa: E402
    FONT_CASCADIA,
    FONT_HELVETICA,
    FONT_VIRGIL,
    GAP_BLOCOS,
    GRID,
    MARGEM_FRAME,
    TAMANHOS,
    cor_sombra,
    get_paleta,
)


# ============================================================
# TEMPLATE 1: FUNIL VERTICAL (5 etapas em trapezios)
# ============================================================
def template_funil(dados, paleta):
    """
    dados = {
        "titulo": "Funil de Vendas",
        "etapas": [
            {"nome": "Trafego", "volume": "10.000", "skill": "ads"},
            {"nome": "Captura", "volume": "2.000", "skill": "lead magnet"},
            ...
        ]
    }
    """
    elementos = []
    titulo = dados.get("titulo", "FUNIL")
    etapas = dados.get("etapas", [])

    # Titulo
    elementos.append(texto(
        100, 60, titulo.upper(), paleta,
        tamanho=TAMANHOS["titulo_diagrama"], fonte=FONT_HELVETICA,
        cor=paleta["dominante"],
    ))

    # Cada etapa = retangulo (faixa) com largura decrescente, centralizada
    largura_max = 600
    altura_etapa = 90
    y = 200
    gap = 16
    cores_degrade = [
        cor_sombra(paleta["dominante"], 90),
        cor_sombra(paleta["dominante"], 75),
        cor_sombra(paleta["dominante"], 60),
        cor_sombra(paleta["dominante"], 45),
        cor_sombra(paleta["dominante"], 30),
    ]

    for i, etapa in enumerate(etapas):
        largura = largura_max - (i * 80)
        x = 100 + (largura_max - largura) / 2
        cor = cores_degrade[min(i, len(cores_degrade) - 1)]

        # Card da etapa
        elementos.extend(card_premium(
            x, y, largura, altura_etapa, paleta,
            etapa["nome"], fill=cor, sombra=(i == 0),
            tamanho_titulo=TAMANHOS["label_bloco"] + 2,
        ))

        # Volume a esquerda (Cascadia mono)
        if etapa.get("volume"):
            elementos.append(texto(
                40, y + altura_etapa / 2 - 12, etapa["volume"], paleta,
                tamanho=20, fonte=FONT_CASCADIA, alinhamento="right",
                cor=paleta["traco"], largura=50,
            ))

        # Skill responsavel a direita (Virgil annotation)
        if etapa.get("skill"):
            elementos.append(texto(
                x + largura + 30, y + altura_etapa / 2 - 8,
                f"← {etapa['skill']}", paleta,
                tamanho=14, fonte=FONT_VIRGIL,
                cor=paleta["neutro_medio"],
            ))

        y += altura_etapa + gap

    return elementos


# ============================================================
# TEMPLATE 2: MATRIZ 2x2
# ============================================================
def template_matriz_2x2(dados, paleta):
    """
    dados = {
        "titulo": "Esforco x Impacto",
        "eixo_x": "Esforco",
        "eixo_y": "Impacto",
        "quadrantes": {
            "alto_alto": "Faca agora",
            "alto_baixo": "Planeje",
            "baixo_alto": "Quick wins",
            "baixo_baixo": "Esqueca"
        }
    }
    """
    elementos = []
    titulo = dados.get("titulo", "MATRIZ 2x2")
    eixo_x = dados.get("eixo_x", "X")
    eixo_y = dados.get("eixo_y", "Y")
    q = dados.get("quadrantes", {})

    elementos.append(texto(
        100, 60, titulo.upper(), paleta,
        tamanho=TAMANHOS["titulo_diagrama"], fonte=FONT_HELVETICA,
        cor=paleta["dominante"],
    ))

    # 4 quadrantes
    base_x, base_y = 200, 200
    tam = 280
    cores = {
        "baixo_alto": cor_sombra(paleta["accent"], 30),   # Q2 esq-cima — quick wins (verde-amarelo)
        "alto_alto": cor_sombra(paleta["dominante"], 30),  # Q1 dir-cima — faca agora (dominante)
        "baixo_baixo": cor_sombra(paleta["neutro_medio"], 20),  # Q3 esq-baixo
        "alto_baixo": cor_sombra(paleta["destaque_quente"], 25),  # Q4 dir-baixo
    }
    posicoes = {
        "baixo_alto": (base_x, base_y),
        "alto_alto": (base_x + tam, base_y),
        "baixo_baixo": (base_x, base_y + tam),
        "alto_baixo": (base_x + tam, base_y + tam),
    }
    for key, (x, y) in posicoes.items():
        elementos.extend(card_premium(
            x, y, tam, tam, paleta,
            q.get(key, "—"),
            fill=cores[key], sombra=False, arredondado_titulo=False,
            tamanho_titulo=20,
        ) if False else card_premium(
            x, y, tam, tam, paleta, q.get(key, "—"),
            fill=cores[key], sombra=False, tamanho_titulo=20,
        ))

    # Eixos (setas elbow saindo do centro)
    cx = base_x + tam
    cy = base_y + tam
    elementos.append(seta(cx, cy, cx + tam + 40, cy, paleta, elbow=True, cor=paleta["traco"], espessura=2))
    elementos.append(seta(cx, cy, cx, cy - tam - 40, paleta, elbow=True, cor=paleta["traco"], espessura=2))

    # Labels dos eixos
    elementos.append(texto(
        cx + tam + 50, cy - 10, eixo_x.upper(), paleta,
        tamanho=16, fonte=FONT_HELVETICA, cor=paleta["traco"],
    ))
    lbl_y = texto(
        cx - 40, cy - tam - 70, eixo_y.upper(), paleta,
        tamanho=16, fonte=FONT_HELVETICA, cor=paleta["traco"],
    )
    elementos.append(lbl_y)

    # Annotation Virgil (premium signature)
    elementos.append(texto(
        base_x, base_y + 2 * tam + 60,
        "← priorize Q superior direito (quick wins)", paleta,
        tamanho=14, fonte=FONT_VIRGIL, cor=paleta["neutro_medio"],
    ))

    return elementos


# ============================================================
# TEMPLATE 3: JORNADA HORIZONTAL (5 fases em sequencia)
# ============================================================
def template_jornada(dados, paleta):
    """
    dados = {
        "titulo": "Jornada do Cliente",
        "fases": [
            {"nome": "Descoberta", "bullets": ["Vê anúncio", "Curioso"], "icone": "👁"},
            ...
        ]
    }
    """
    elementos = []
    titulo = dados.get("titulo", "JORNADA")
    fases = dados.get("fases", [])

    elementos.append(texto(
        100, 60, titulo.upper(), paleta,
        tamanho=TAMANHOS["titulo_diagrama"], fonte=FONT_HELVETICA,
        cor=paleta["dominante"],
    ))

    x_inicio = 100
    y = 200
    largura_fase = 240
    altura_fase = 320
    gap = 32

    # Linha continua atravessando as fases (fio condutor)
    n = len(fases)
    if n > 1:
        x_fim = x_inicio + n * largura_fase + (n - 1) * gap
        elementos.append(linha(
            x_inicio - 20, y + altura_fase + 40,
            x_fim + 20, y + altura_fase + 40,
            paleta, espessura=2, cor=paleta["accent"],
        ))

    for i, fase in enumerate(fases):
        x = x_inicio + i * (largura_fase + gap)

        # Frame da fase
        elementos.extend(container_secao(
            x, y, largura_fase, altura_fase,
            f"{i+1:02d} {fase['nome']}", paleta,
        ))

        # Marcador na linha (circulo)
        elementos.append(elipse(
            x + largura_fase / 2 - 12, y + altura_fase + 28,
            24, 24, paleta, fill=paleta["accent"],
        ))

        # Icone (texto grande Helvetica) ou nome
        if fase.get("icone"):
            elementos.append(texto(
                x + largura_fase / 2 - 24, y + 40,
                fase["icone"], paleta,
                tamanho=64, alinhamento="center",
            ))

        # Bullets em Virgil (annotation humanizada)
        for j, b in enumerate(fase.get("bullets", [])[:3]):
            elementos.append(texto(
                x + 20, y + 160 + j * 28,
                f"• {b}", paleta,
                tamanho=14, fonte=FONT_VIRGIL,
                cor=paleta["traco"],
            ))

    return elementos


# ============================================================
# TEMPLATE 4: HUB & SPOKE
# ============================================================
def template_hub_spoke(dados, paleta):
    """
    dados = {
        "titulo": "Metodo X",
        "centro": "Nome Central",
        "raios": ["Item 1", "Item 2", ...]
    }
    """
    import math
    elementos = []
    titulo = dados.get("titulo", "")
    centro_nome = dados.get("centro", "CENTRO")
    raios = dados.get("raios", [])

    if titulo:
        elementos.append(texto(
            100, 60, titulo.upper(), paleta,
            tamanho=TAMANHOS["titulo_diagrama"], fonte=FONT_HELVETICA,
            cor=paleta["dominante"],
        ))

    cx, cy = 700, 500
    raio_centro = 100
    raio_orbita = 320

    # Centro
    centro_el = elipse(
        cx - raio_centro, cy - raio_centro,
        raio_centro * 2, raio_centro * 2, paleta,
        fill=paleta["dominante"],
    )
    centro_el["strokeColor"] = paleta["accent"]
    centro_el["strokeWidth"] = 3
    elementos.append(centro_el)
    txt_centro = texto(
        cx - raio_centro, cy - 14, centro_nome, paleta,
        tamanho=20, fonte=FONT_HELVETICA, alinhamento="center", vertical="middle",
        cor=paleta["background"], container_id=centro_el["id"], largura=raio_centro * 2,
    )
    txt_centro["x"] = cx - raio_centro
    txt_centro["y"] = cy - raio_centro
    txt_centro["width"] = raio_centro * 2
    txt_centro["height"] = raio_centro * 2
    centro_el["boundElements"] = [{"type": "text", "id": txt_centro["id"]}]
    elementos.append(txt_centro)

    # Anel decorativo tracejado
    anel = elipse(
        cx - raio_orbita - 60, cy - raio_orbita - 60,
        (raio_orbita + 60) * 2, (raio_orbita + 60) * 2, paleta,
    )
    anel["strokeStyle"] = "dashed"
    anel["strokeColor"] = paleta["neutro_medio"]
    anel["backgroundColor"] = "transparent"
    elementos.append(anel)

    # Raios ao redor
    n = len(raios)
    if n == 0:
        return elementos

    raio_card = 80
    for i, raio in enumerate(raios):
        angulo = (2 * math.pi * i / n) - math.pi / 2
        px = cx + math.cos(angulo) * raio_orbita - raio_card
        py = cy + math.sin(angulo) * raio_orbita - raio_card / 2

        card_els = card_premium(
            int(px), int(py), raio_card * 2, raio_card, paleta,
            raio, fill=paleta["background"], sombra=True,
        )
        card_principal = card_els[1] if len(card_els) > 1 else card_els[0]
        elementos.extend(card_els)

        # Conector centro -> card
        elementos.extend(conector_inteligente(centro_el, card_principal, paleta, elbow=True))

    # Annotation Virgil (premium signature)
    elementos.append(texto(
        cx - 200, cy + raio_orbita + 100,
        "← o centro orquestra. os raios executam.", paleta,
        tamanho=14, fonte=FONT_VIRGIL, cor=paleta["neutro_medio"],
    ))

    return elementos


# ============================================================
# TEMPLATE 5: TIMELINE HORIZONTAL
# ============================================================
def template_timeline(dados, paleta):
    """
    dados = {
        "titulo": "Roadmap 2026",
        "eventos": [
            {"data": "Jan", "nome": "Lancamento", "descricao": "..."},
            ...
        ]
    }
    """
    elementos = []
    titulo = dados.get("titulo", "")
    eventos = dados.get("eventos", [])

    if titulo:
        elementos.append(texto(
            100, 60, titulo.upper(), paleta,
            tamanho=TAMANHOS["titulo_diagrama"], fonte=FONT_HELVETICA,
            cor=paleta["dominante"],
        ))

    x_inicio = 120
    y_linha = 400
    n = len(eventos)
    if n < 2:
        return elementos
    largura_total = 1200
    espacamento = largura_total / (n - 1)

    # Linha horizontal (espessura uniforme 2px)
    elementos.append(linha(
        x_inicio, y_linha, x_inicio + largura_total, y_linha,
        paleta, espessura=2, cor=paleta["traco"],
    ))

    for i, ev in enumerate(eventos):
        x = x_inicio + int(i * espacamento)
        acima = (i % 2 == 0)

        # Marcador circular
        elementos.append(elipse(
            x - 12, y_linha - 12, 24, 24, paleta,
            fill=paleta["accent"],
        ))

        # Data em mono
        elementos.append(texto(
            x - 30, y_linha + 24, ev.get("data", ""), paleta,
            tamanho=14, fonte=FONT_CASCADIA,
            cor=paleta["neutro_medio"], alinhamento="center", largura=60,
        ))

        # Card com nome do evento (acima ou abaixo da linha)
        y_card = y_linha - 140 if acima else y_linha + 60
        elementos.extend(card_premium(
            x - 90, y_card, 180, 70, paleta,
            ev.get("nome", ""), fill=paleta["background"],
            tamanho_titulo=14,
        ))

        # Linha conectando marcador ao card (espessura uniforme 2px tracejada)
        y_conector_ini = y_linha
        y_conector_fim = y_card + 70 if acima else y_card
        elementos.append(linha(
            x, y_conector_ini, x, y_conector_fim,
            paleta, tracejada=True, espessura=2,
            cor=paleta["neutro_medio"],
        ))

    # Annotation Virgil (premium signature)
    elementos.append(texto(
        x_inicio, y_linha + 200,
        "obs: cada marco move o ponteiro do negocio.", paleta,
        tamanho=14, fonte=FONT_VIRGIL, cor=paleta["neutro_medio"],
    ))

    return elementos


# ============================================================
# TEMPLATE 6: MAPA MENTAL (centro + ramos)
# ============================================================
def template_mapa_mental(dados, paleta):
    """
    dados = {
        "centro": "Ideia central",
        "ramos": [
            {"nome": "Ramo 1", "sub": ["sub a", "sub b"]},
            ...
        ]
    }
    """
    import math
    elementos = []
    centro = dados.get("centro", "")
    ramos = dados.get("ramos", [])

    # Titulo grande (premium signature)
    elementos.append(texto(
        100, 60, "MAPA MENTAL", paleta,
        tamanho=TAMANHOS["titulo_diagrama"], fonte=FONT_HELVETICA,
        cor=paleta["dominante"],
    ))

    cx, cy = 800, 600
    # Nó central
    centro_w, centro_h = 280, 100
    centro_el = retangulo(
        cx - centro_w / 2, cy - centro_h / 2, centro_w, centro_h, paleta,
        fill=paleta["dominante"], arredondado=True,
    )
    centro_el["strokeColor"] = paleta["accent"]
    centro_el["strokeWidth"] = 3
    elementos.append(centro_el)
    txt_c = texto(
        cx - centro_w / 2, cy - 16, centro.upper(), paleta,
        tamanho=22, fonte=FONT_HELVETICA, alinhamento="center", vertical="middle",
        cor=paleta["background"], container_id=centro_el["id"], largura=centro_w,
    )
    txt_c["x"] = cx - centro_w / 2
    txt_c["y"] = cy - centro_h / 2
    txt_c["width"] = centro_w
    txt_c["height"] = centro_h
    centro_el["boundElements"] = [{"type": "text", "id": txt_c["id"]}]
    elementos.append(txt_c)

    n = len(ramos)
    if n == 0:
        return elementos

    raio_orbita = 360
    raio_card_w = 200
    raio_card_h = 60

    for i, ramo in enumerate(ramos):
        ang = (2 * math.pi * i / n) - math.pi / 2
        px = cx + math.cos(ang) * raio_orbita
        py = cy + math.sin(ang) * raio_orbita

        ramo_card = card_premium(
            int(px - raio_card_w / 2), int(py - raio_card_h / 2),
            raio_card_w, raio_card_h, paleta,
            ramo.get("nome", ""), fill=paleta["background"],
            tamanho_titulo=16,
        )
        elementos.extend(ramo_card)
        ramo_principal = ramo_card[1]
        elementos.extend(conector_inteligente(centro_el, ramo_principal, paleta, elbow=True))

        # Sub-ramos (max 3 por ramo)
        subs = ramo.get("sub", [])[:3]
        for j, sub in enumerate(subs):
            ang_sub = ang + (j - len(subs) / 2 + 0.5) * 0.25
            sx = px + math.cos(ang_sub) * 200
            sy = py + math.sin(ang_sub) * 100 + (j - 1) * 30
            sub_el = texto(
                int(sx), int(sy), f"• {sub}", paleta,
                tamanho=14, fonte=FONT_VIRGIL,
                cor=paleta["neutro_medio"],
            )
            elementos.append(sub_el)

    return elementos


# ============================================================
# DISPATCHER
# ============================================================
TEMPLATES = {
    "funil": template_funil,
    "matriz_2x2": template_matriz_2x2,
    "jornada": template_jornada,
    "hub_spoke": template_hub_spoke,
    "timeline": template_timeline,
    "mapa_mental": template_mapa_mental,
}


def main():
    parser = argparse.ArgumentParser(description="Gerador de diagrama premium Excalidraw")
    parser.add_argument("--template", required=True, choices=list(TEMPLATES.keys()))
    parser.add_argument("--dados", help="Caminho do JSON com dados do diagrama")
    parser.add_argument("--paleta", default="imperatriz",
                        choices=["imperatriz", "mckinsey", "dark_premium", "notion_minimal"])
    parser.add_argument("--saida", required=True, help="Caminho do arquivo .excalidraw")
    parser.add_argument("--obsidian", action="store_true",
                        help="Tambem salva .excalidraw.md pra Obsidian")
    parser.add_argument("--titulo-obsidian", default="Diagrama Imperatriz")
    args = parser.parse_args()

    paleta = get_paleta(args.paleta)
    modo_dark = args.paleta == "dark_premium"

    if args.dados:
        dados = json.loads(Path(args.dados).expanduser().read_text(encoding="utf-8"))
    else:
        dados = {}

    fn = TEMPLATES[args.template]
    elementos = fn(dados, paleta)

    # Envelopa em Frame nomeado (sobe nota auditoria + organiza)
    nome_frame = dados.get("titulo") or args.template.replace("_", " ").upper()
    elementos = envelopa_em_frame(elementos, nome_frame.upper(), paleta)

    cena = cena_excalidraw(elementos, paleta, modo_dark=modo_dark)

    p_excalidraw = salvar(cena, args.saida, formato="excalidraw")
    print(f"✓ Excalidraw salvo: {p_excalidraw}")

    if args.obsidian:
        md = cena_obsidian_md(elementos, paleta, modo_dark=modo_dark, titulo=args.titulo_obsidian)
        p_md = str(p_excalidraw).replace(".excalidraw", ".excalidraw.md")
        salvar(md, p_md, formato="md")
        print(f"✓ Obsidian .md salvo: {p_md}")


if __name__ == "__main__":
    main()
