#!/usr/bin/env python3
"""
Menu interativo de instalação de Skills Fluig.
Gerencia skills para: Claude Code, VS Code + Claude, Codex CLI, GitHub Copilot, Cursor.
"""
import os
import sys
import shutil

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

# ── Cores ANSI ────────────────────────────────────────────────
R   = "\033[0m"
B   = "\033[1m"
DIM = "\033[2m"
CY  = "\033[96m"
GR  = "\033[92m"
YL  = "\033[93m"
RD  = "\033[91m"
MG  = "\033[95m"
BL  = "\033[94m"
BG_SEL  = "\033[44m"   # fundo azul (selecionado)
BG_DONE = "\033[42m"   # fundo verde (instalado)

TICK  = f"{GR}✓{R}"
CROSS = f"{RD}✗{R}"
DASH  = f"{DIM}—{R}"
ARROW = f"{CY}›{R}"

def clr():
    os.system("cls" if os.name == "nt" else "clear")

def banner():
    print(f"""
{CY}{B}╔══════════════════════════════════════════════════════════╗
║                                                          ║
║   {MG}Fluig Skills Installer{CY}                                   ║
║   {DIM}Gerencie skills para Claude Code, Codex, Copilot, Cursor{CY} ║
║                                                          ║
╚══════════════════════════════════════════════════════════╝{R}
""")

def linha(char="─", cor=DIM, largura=60):
    print(f"{cor}{char * largura}{R}")

def ok(msg):   print(f"  {TICK}  {msg}")
def warn(msg): print(f"  {YL}⚠{R}  {msg}")
def erro(msg): print(f"  {CROSS}  {msg}")
def info(msg): print(f"  {CY}→{R}  {msg}")

def ask(prompt, default=""):
    suf = f" {DIM}[{default}]{R}" if default else ""
    try:
        v = input(f"  {B}{prompt}{R}{suf}: ").strip()
        return v if v else default
    except (KeyboardInterrupt, EOFError):
        print()
        return default

def pausar():
    try:
        input(f"\n  {DIM}Pressione Enter para continuar...{R}")
    except (KeyboardInterrupt, EOFError):
        pass

# ── Dados das skills e destinos ───────────────────────────────

SKILLS_INFO = [
    ("fluig-datasets",           "Datasets JS/JDBC/ServiceManager",               "📦"),
    ("fluig-eventos-formulario",  "Eventos de formulário (validateForm, afterSave)","📝"),
    ("fluig-eventos-processo",    "Eventos de processo (afterTaskComplete...)",     "⚙️ "),
    ("fluig-formularios",         "Formulários HTML com Style Guide",               "🖼️ "),
    ("fluig-integracoes",         "Integrações REST e ServiceManager",              "🔌"),
    ("fluig-process-reader",      "Leitura e análise de arquivos .process",         "🔍"),
    ("fluig-scripts-avancados",   "Scripts avançados (subprocesso, notificações)",  "🚀"),
    ("fluig-widgets",             "Widgets WCM com SuperWidget",                    "🧩"),
]

DESTINOS_INFO = [
    ("claude_global",   "Claude Code global",   "~/.claude/skills/",                                     "copy"),
    ("claude_projeto",  "Claude Code projeto",  "{projeto}/.claude/skills/",                              "copy"),
    ("codex_global",    "Codex CLI global",     "~/.codex/instructions.md",                               "md"),
    ("codex_projeto",   "Codex CLI projeto",    "{projeto}/.codex/instructions.md",                       "md"),
    ("copilot",         "GitHub Copilot",       "{projeto}/.github/copilot-instructions.md",              "md"),
    ("cursor",          "Cursor",               "{projeto}/.cursor/rules/{skill}.mdc",                    "mdc"),
]

PRECISAM_PROJETO = {"claude_projeto", "codex_projeto", "copilot", "cursor"}

# ── Detecção de status ────────────────────────────────────────

def _detectar_status(skills_selecionadas: set, destinos_selecionados: set, caminho_projeto: str) -> dict:
    """Retorna dict {skill: {destino: bool}} com o status de instalação."""
    from pathlib import Path
    from tools.dev.skills_installer import _skills_dir

    home = str(Path.home())
    status = {}

    for skill, _, _ in SKILLS_INFO:
        status[skill] = {}
        for key, _, _, _ in DESTINOS_INFO:
            instalado = False
            try:
                if key == "claude_global":
                    instalado = os.path.isdir(os.path.join(home, ".claude", "skills", skill))
                elif key == "claude_projeto" and caminho_projeto:
                    instalado = os.path.isdir(os.path.join(caminho_projeto, ".claude", "skills", skill))
                elif key == "codex_global":
                    f = os.path.join(home, ".codex", "instructions.md")
                    instalado = os.path.isfile(f) and f"# Fluig Skill: {skill}" in open(f, encoding="utf-8").read()
                elif key == "codex_projeto" and caminho_projeto:
                    f = os.path.join(caminho_projeto, ".codex", "instructions.md")
                    instalado = os.path.isfile(f) and f"# Fluig Skill: {skill}" in open(f, encoding="utf-8").read()
                elif key == "copilot" and caminho_projeto:
                    f = os.path.join(caminho_projeto, ".github", "copilot-instructions.md")
                    instalado = os.path.isfile(f) and f"# Fluig Skill: {skill}" in open(f, encoding="utf-8").read()
                elif key == "cursor" and caminho_projeto:
                    instalado = os.path.isfile(os.path.join(caminho_projeto, ".cursor", "rules", f"{skill}.mdc"))
            except Exception:
                instalado = False
            status[skill][key] = instalado

    return status


# ── Telas do menu ─────────────────────────────────────────────

def tela_selecionar_skills(pre_sel: set = None) -> set:
    """Tela de seleção de skills. Retorna set com os nomes selecionados."""
    selecionadas = set(pre_sel) if pre_sel else set()

    while True:
        clr()
        banner()
        print(f"  {B}Selecione as skills para instalar{R}  {DIM}(Enter = confirmar, A = todas, N = nenhuma){R}\n")
        linha()

        for i, (nome, desc, icone) in enumerate(SKILLS_INFO, 1):
            marcado = nome in selecionadas
            check = f"{GR}[✓]{R}" if marcado else f"{DIM}[ ]{R}"
            num   = f"{CY}{i}{R}"
            print(f"  {check} {num}  {icone} {B}{nome}{R}")
            print(f"          {DIM}{desc}{R}")

        linha()
        print(f"  {DIM}Selecionadas: {GR}{len(selecionadas)}{DIM}/{len(SKILLS_INFO)}{R}\n")

        resp = ask("Número para alternar (1-8), A=todas, N=nenhuma, Enter=confirmar", "")

        if resp == "":
            break
        elif resp.lower() == "a":
            selecionadas = {s[0] for s in SKILLS_INFO}
        elif resp.lower() == "n":
            selecionadas = set()
        else:
            try:
                for parte in resp.replace(",", " ").split():
                    idx = int(parte) - 1
                    if 0 <= idx < len(SKILLS_INFO):
                        nome = SKILLS_INFO[idx][0]
                        if nome in selecionadas:
                            selecionadas.discard(nome)
                        else:
                            selecionadas.add(nome)
            except ValueError:
                warn("Entrada inválida — use números separados por espaço ou vírgula")

    return selecionadas


def tela_selecionar_destinos(pre_sel: set = None) -> set:
    """Tela de seleção de destinos. Retorna set com os keys selecionados."""
    selecionados = set(pre_sel) if pre_sel else {"claude_global"}

    while True:
        clr()
        banner()
        print(f"  {B}Selecione os destinos de instalação{R}  {DIM}(Enter = confirmar, A = todos, N = nenhum){R}\n")
        linha()

        for i, (key, nome, caminho, _) in enumerate(DESTINOS_INFO, 1):
            marcado = key in selecionados
            check   = f"{GR}[✓]{R}" if marcado else f"{DIM}[ ]{R}"
            proj    = f" {YL}(requer projeto){R}" if key in PRECISAM_PROJETO else ""
            print(f"  {check} {CY}{i}{R}  {B}{nome}{R}{proj}")
            print(f"          {DIM}{caminho}{R}")

        linha()
        print(f"  {DIM}Selecionados: {GR}{len(selecionados)}{DIM}/{len(DESTINOS_INFO)}{R}\n")

        resp = ask("Número para alternar (1-6), A=todos, N=nenhum, Enter=confirmar", "")

        if resp == "":
            break
        elif resp.lower() == "a":
            selecionados = {d[0] for d in DESTINOS_INFO}
        elif resp.lower() == "n":
            selecionados = set()
        else:
            try:
                for parte in resp.replace(",", " ").split():
                    idx = int(parte) - 1
                    if 0 <= idx < len(DESTINOS_INFO):
                        key = DESTINOS_INFO[idx][0]
                        if key in selecionados:
                            selecionados.discard(key)
                        else:
                            selecionados.add(key)
            except ValueError:
                warn("Entrada inválida")

    return selecionados


def tela_caminho_projeto(destinos: set) -> str:
    """Solicita caminho do projeto se algum destino precisar."""
    if not (destinos & PRECISAM_PROJETO):
        return ""

    clr()
    banner()
    print(f"  {B}Caminho do projeto{R}\n")
    linha()
    print(f"  Os destinos selecionados requerem o caminho do projeto:\n")
    for key in destinos & PRECISAM_PROJETO:
        nome = next(d[1] for d in DESTINOS_INFO if d[0] == key)
        print(f"    {CY}•{R} {nome}")

    print()
    caminho = ask("Caminho absoluto do projeto", default=os.getcwd())
    return caminho.strip()


def tela_extras(destinos: set) -> tuple[bool, bool]:
    """Pergunta sobre agente e regras se Claude Code estiver selecionado."""
    claude_selecionado = bool(destinos & {"claude_global", "claude_projeto"})
    if not claude_selecionado:
        return False, False

    clr()
    banner()
    print(f"  {B}Extras para Claude Code{R}\n")
    linha()

    print(f"  {CY}Agente fluig-developer{R}")
    print(f"  {DIM}Agente especializado em desenvolvimento Fluig para Claude Code{R}\n")
    instalar_agente = ask("Instalar agente fluig-developer?", "s").lower() in ("s", "sim", "y", "yes")

    print(f"\n  {CY}Regras de código Fluig{R}")
    print(f"  {DIM}rule-es5-serverside · rule-nomenclatura · rule-seguranca{R}\n")
    instalar_regras = ask("Instalar regras?", "s").lower() in ("s", "sim", "y", "yes")

    return instalar_agente, instalar_regras


def tela_confirmacao(skills: set, destinos: set, caminho_projeto: str,
                     instalar_agente: bool, instalar_regras: bool) -> bool:
    """Exibe resumo e pede confirmação final."""
    clr()
    banner()
    print(f"  {B}Resumo da instalação{R}\n")
    linha()

    print(f"  {B}Skills selecionadas ({len(skills)}):{R}")
    for s in sorted(skills):
        icone = next((i[2] for i in SKILLS_INFO if i[0] == s), "•")
        print(f"    {GR}✓{R} {icone} {s}")

    print(f"\n  {B}Destinos ({len(destinos)}):{R}")
    for key in [d[0] for d in DESTINOS_INFO if d[0] in destinos]:
        nome   = next(d[1] for d in DESTINOS_INFO if d[0] == key)
        caminho = next(d[2] for d in DESTINOS_INFO if d[0] == key)
        proj    = f"  {DIM}({caminho_projeto}){R}" if key in PRECISAM_PROJETO and caminho_projeto else ""
        print(f"    {CY}→{R} {B}{nome}{R}{proj}")

    if instalar_agente or instalar_regras:
        print(f"\n  {B}Extras:{R}")
        if instalar_agente: print(f"    {GR}✓{R} Agente fluig-developer")
        if instalar_regras: print(f"    {GR}✓{R} Regras ES5 / nomenclatura / segurança")

    linha()
    resp = ask(f"\n  {B}Confirmar instalação?{R} (s/n)", "s")
    return resp.lower() in ("s", "sim", "y", "yes")


def tela_instalando(skills: set, destinos: set, caminho_projeto: str,
                    instalar_agente: bool, instalar_regras: bool):
    """Executa a instalação com feedback visual."""
    from pathlib import Path
    from tools.dev.skills_installer import (
        _listar_skills_disponiveis,
        _instalar_claude_code, _instalar_codex,
        _instalar_copilot, _instalar_cursor,
        _instalar_agente as _ag,
        _instalar_regras as _rg,
    )

    clr()
    banner()
    print(f"  {B}Instalando...{R}\n")
    linha()

    home = str(Path.home())
    skills_map = {s["nome"]: s["caminho"] for s in _listar_skills_disponiveis()}
    erros = []

    for skill in sorted(skills):
        if skill not in skills_map:
            warn(f"{skill} — não encontrada na pasta fonte")
            continue

        skill_path = skills_map[skill]
        print(f"\n  {CY}{B}{skill}{R}")

        for key, nome_dest, _, _ in DESTINOS_INFO:
            if key not in destinos:
                continue

            try:
                if key == "claude_global":
                    _instalar_claude_code(skill, skill_path, os.path.join(home, ".claude"))
                elif key == "claude_projeto":
                    _instalar_claude_code(skill, skill_path, os.path.join(caminho_projeto, ".claude"))
                elif key == "codex_global":
                    _instalar_codex(skill, skill_path, os.path.join(home, ".codex"))
                elif key == "codex_projeto":
                    _instalar_codex(skill, skill_path, os.path.join(caminho_projeto, ".codex"))
                elif key == "copilot":
                    _instalar_copilot(skill, skill_path, caminho_projeto)
                elif key == "cursor":
                    _instalar_cursor(skill, skill_path, caminho_projeto)
                print(f"    {TICK} {nome_dest}")
            except Exception as e:
                print(f"    {CROSS} {nome_dest}  {DIM}{e}{R}")
                erros.append(f"{skill} / {nome_dest}: {e}")

    # Extras
    if instalar_agente or instalar_regras:
        print(f"\n  {CY}{B}Extras{R}")
        if instalar_agente:
            for base in ([os.path.join(home, ".claude")] +
                         ([os.path.join(caminho_projeto, ".claude")] if "claude_projeto" in destinos and caminho_projeto else [])):
                try:
                    _ag(base)
                    print(f"    {TICK} fluig-developer.md → {base}")
                except Exception as e:
                    print(f"    {CROSS} {e}")

        if instalar_regras:
            for base in ([os.path.join(home, ".claude")] +
                         ([os.path.join(caminho_projeto, ".claude")] if "claude_projeto" in destinos and caminho_projeto else [])):
                try:
                    resultados = _rg(base)
                    for r in resultados:
                        print(f"    {TICK} {r}")
                except Exception as e:
                    print(f"    {CROSS} {e}")

    # Resultado final
    print()
    linha()
    if not erros:
        print(f"\n  {GR}{B}Instalação concluída com sucesso!{R}")
    else:
        print(f"\n  {YL}Instalação concluída com {len(erros)} erro(s):{R}")
        for e in erros:
            print(f"    {CROSS} {e}")
    print()


def tela_status(caminho_projeto: str = ""):
    """Tela de status mostrando o que está instalado onde."""
    clr()
    banner()
    print(f"  {B}Status das Skills{R}  {DIM}(o que está instalado onde){R}\n")

    if not caminho_projeto:
        caminho_projeto = ask("Caminho do projeto para verificar (Enter para pular)", "")

    linha()
    status = _detectar_status(set(), set(), caminho_projeto)

    # Cabeçalho das colunas
    dest_labels = ["CL.G", "CL.P", "CDX.G", "CDX.P", "CPLT", "CRSR"]
    header = f"  {'Skill':<32}" + "  ".join(f"{DIM}{d:^5}{R}" for d in dest_labels)
    print(f"\n{header}")
    linha("─", DIM, 60)

    for skill, _, _ in SKILLS_INFO:
        st = status.get(skill, {})
        cols = []
        for key, _, _, _ in DESTINOS_INFO:
            inst = st.get(key, False)
            if key in PRECISAM_PROJETO and not caminho_projeto:
                cols.append(f"{DIM}  ?  {R}")
            elif inst:
                cols.append(f"{GR}  ✓  {R}")
            else:
                cols.append(f"{DIM}  —  {R}")
        nome_short = skill.replace("fluig-", "")[:28]
        print(f"  {nome_short:<32}" + "".join(cols))

    linha("─", DIM, 60)
    print(f"\n  {DIM}CL.G=Claude Global  CL.P=Claude Projeto  CDX.G=Codex Global")
    print(f"  CDX.P=Codex Projeto  CPLT=Copilot  CRSR=Cursor{R}\n")
    pausar()


def tela_remover():
    """Tela para remover skills de um destino."""
    clr()
    banner()
    print(f"  {B}Remover Skills{R}\n")
    linha()

    # Selecionar destino
    print(f"  Selecione o destino:\n")
    for i, (key, nome, caminho, _) in enumerate(DESTINOS_INFO, 1):
        print(f"  {CY}{i}{R}  {B}{nome}{R}  {DIM}{caminho}{R}")

    print()
    resp = ask("Número do destino", "1")
    try:
        idx = int(resp) - 1
        destino_key = DESTINOS_INFO[idx][0]
        destino_nome = DESTINOS_INFO[idx][1]
    except (ValueError, IndexError):
        warn("Seleção inválida.")
        pausar()
        return

    caminho_projeto = ""
    if destino_key in PRECISAM_PROJETO:
        caminho_projeto = ask("Caminho do projeto", os.getcwd())

    # Selecionar skills
    skills = tela_selecionar_skills()
    if not skills:
        warn("Nenhuma skill selecionada.")
        pausar()
        return

    clr()
    banner()
    print(f"  {B}Confirmação de remoção{R}\n")
    print(f"  Destino: {RD}{destino_nome}{R}")
    print(f"  Skills:  {', '.join(sorted(skills))}\n")

    if ask("Confirmar remoção?", "n").lower() not in ("s", "sim", "y", "yes"):
        info("Cancelado.")
        pausar()
        return

    from tools.dev.skills_installer import (
        _instalar_claude_code, _instalar_codex, _instalar_copilot, _instalar_cursor
    )
    import re
    from pathlib import Path
    home = str(Path.home())

    print()
    for skill in sorted(skills):
        try:
            if destino_key == "claude_global":
                path = os.path.join(home, ".claude", "skills", skill)
                if os.path.isdir(path):
                    shutil.rmtree(path)
                    ok(f"{skill} removida de ~/.claude/skills/")
                else:
                    warn(f"{skill} não estava instalada")

            elif destino_key == "claude_projeto":
                path = os.path.join(caminho_projeto, ".claude", "skills", skill)
                if os.path.isdir(path):
                    shutil.rmtree(path)
                    ok(f"{skill} removida do projeto")
                else:
                    warn(f"{skill} não estava instalada no projeto")

            elif destino_key in ("codex_global", "codex_projeto"):
                instructions = (os.path.join(home, ".codex", "instructions.md")
                                if destino_key == "codex_global"
                                else os.path.join(caminho_projeto, ".codex", "instructions.md"))
                if os.path.isfile(instructions):
                    content = open(instructions, encoding="utf-8").read()
                    pattern = rf"# Fluig Skill: {re.escape(skill)}.*?(?=\n# Fluig Skill:|\Z)"
                    novo = re.sub(pattern, "", content, flags=re.DOTALL).strip()
                    with open(instructions, "w", encoding="utf-8") as f:
                        f.write(novo + "\n")
                    ok(f"{skill} removida de {instructions}")
                else:
                    warn(f"instructions.md não encontrado")

            elif destino_key == "copilot":
                instructions = os.path.join(caminho_projeto, ".github", "copilot-instructions.md")
                if os.path.isfile(instructions):
                    content = open(instructions, encoding="utf-8").read()
                    pattern = rf"# Fluig Skill: {re.escape(skill)}.*?(?=\n# Fluig Skill:|\Z)"
                    novo = re.sub(pattern, "", content, flags=re.DOTALL).strip()
                    with open(instructions, "w", encoding="utf-8") as f:
                        f.write(novo + "\n")
                    ok(f"{skill} removida de copilot-instructions.md")
                else:
                    warn(f"copilot-instructions.md não encontrado")

            elif destino_key == "cursor":
                mdc = os.path.join(caminho_projeto, ".cursor", "rules", f"{skill}.mdc")
                if os.path.isfile(mdc):
                    os.remove(mdc)
                    ok(f"{skill}.mdc removido")
                else:
                    warn(f"{skill}.mdc não encontrado")

        except Exception as e:
            erro(f"{skill}: {e}")

    pausar()


# ── Menu principal ────────────────────────────────────────────

def menu_principal():
    skills_sel:  set = set()
    destinos_sel: set = {"claude_global"}
    caminho_projeto: str = ""
    instalar_agente: bool = False
    instalar_regras: bool = False

    while True:
        clr()
        banner()

        # Resumo do estado atual
        if skills_sel:
            info(f"{GR}{len(skills_sel)}{R} skill(s) selecionada(s):  {DIM}{', '.join(sorted(skills_sel))}{R}")
        else:
            info(f"{YL}Nenhuma skill selecionada{R}")

        dest_nomes = [d[1] for d in DESTINOS_INFO if d[0] in destinos_sel]
        info(f"Destinos:  {DIM}{', '.join(dest_nomes) if dest_nomes else 'nenhum'}{R}")

        if caminho_projeto:
            info(f"Projeto:   {DIM}{caminho_projeto}{R}")

        print()
        linha()
        print(f"""
  {CY}1{R}  {B}Selecionar skills{R}          escolher quais skills instalar
  {CY}2{R}  {B}Selecionar destinos{R}        Claude Code, Codex, Copilot, Cursor...
  {CY}3{R}  {B}Definir caminho do projeto{R} necessário para destinos por projeto
  {CY}4{R}  {B}Instalar agora{R}             {GR if skills_sel and destinos_sel else YL}{'pronto!' if skills_sel and destinos_sel else 'selecione skills e destinos primeiro'}{R}
  {DIM}────────────────────────────────────────────────────{R}
  {CY}5{R}  {DIM}Ver status (o que está instalado){R}
  {CY}6{R}  {DIM}Remover skills instaladas{R}
  {DIM}────────────────────────────────────────────────────{R}
  {CY}0{R}  {DIM}Sair{R}
""")
        linha()

        try:
            opcao = input(f"  {B}Opção:{R} ").strip()
        except (KeyboardInterrupt, EOFError):
            break

        if opcao == "1":
            skills_sel = tela_selecionar_skills(skills_sel)

        elif opcao == "2":
            destinos_sel = tela_selecionar_destinos(destinos_sel)

        elif opcao == "3":
            clr()
            banner()
            print(f"  {B}Caminho do projeto{R}\n")
            linha()
            caminho_projeto = ask("Caminho absoluto do projeto", default=caminho_projeto or os.getcwd())

        elif opcao == "4":
            if not skills_sel:
                clr(); banner()
                warn("Nenhuma skill selecionada. Use a opção 1 primeiro.")
                pausar()
                continue
            if not destinos_sel:
                clr(); banner()
                warn("Nenhum destino selecionado. Use a opção 2 primeiro.")
                pausar()
                continue

            # Verificar projeto necessário
            if (destinos_sel & PRECISAM_PROJETO) and not caminho_projeto:
                clr(); banner()
                warn("Os destinos selecionados precisam de um caminho de projeto.")
                caminho_projeto = ask("Caminho do projeto", default=os.getcwd())

            # Perguntar extras
            instalar_agente, instalar_regras = tela_extras(destinos_sel)

            # Confirmação
            if tela_confirmacao(skills_sel, destinos_sel, caminho_projeto,
                                instalar_agente, instalar_regras):
                tela_instalando(skills_sel, destinos_sel, caminho_projeto,
                                instalar_agente, instalar_regras)
                pausar()

        elif opcao == "5":
            tela_status(caminho_projeto)

        elif opcao == "6":
            tela_remover()

        elif opcao == "0":
            break

    clr()
    print(f"\n  {DIM}Fluig Skills Installer — até mais!{R}\n")


if __name__ == "__main__":
    menu_principal()
