#!/usr/bin/env bash
# init_cli_app
# ------------
# Scaffold de Go CLI app con subcomandos, opcionalmente con TUI Bubbletea.
#
# Genera main.go con routing de subcomandos (os.Args + switch), cmd_version.go,
# cmd_status.go, Makefile, .gitignore, go.mod y app.md.
#
# Con --with-tui genera ademas model.go con un modelo Bubbletea base y main.go
# arranca la TUI con tea.NewProgram().Run() en modo fullscreen.
#
# USO:
#   ./init_cli_app.sh <nombre> [--with-tui]
#
# EJEMPLOS:
#   ./init_cli_app.sh my_cli
#   ./init_cli_app.sh deploy_helper --with-tui

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REGISTRY_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"

source "$REGISTRY_ROOT/bash/functions/shell/assert_command_exists.sh"

NOMBRE=""
WITH_TUI="false"

while [ $# -gt 0 ]; do
    case "$1" in
        --with-tui) WITH_TUI="true"; shift ;;
        -h|--help) grep "^#" "$0" | sed 's/^# \?//' ; exit 0 ;;
        -*) echo "Flag desconocido: $1" >&2 ; exit 1 ;;
        *)
            if [ -z "$NOMBRE" ]; then NOMBRE="$1"
            else echo "Argumento extra ignorado: $1" >&2
            fi
            shift ;;
    esac
done

if [ -z "$NOMBRE" ]; then
    echo "Uso: $0 <nombre> [--with-tui]" >&2
    exit 1
fi

APP_DIR="${REGISTRY_ROOT}/apps/${NOMBRE}"
if [ -d "$APP_DIR" ]; then
    echo "ERROR: ${APP_DIR} ya existe. Abortando." >&2
    exit 1
fi

echo ""
echo "════════════════════════════════════════════════════════════"
echo "  INIT CLI APP: ${NOMBRE}"
echo "  Directorio: ${APP_DIR}"
echo "  TUI:        ${WITH_TUI}"
echo "════════════════════════════════════════════════════════════"
echo ""

# ── 1. Verificar Go ──────────────────────────────────────────

echo "[1/5] Verificando herramientas..."
assert_command_exists go
echo "  Go: $(go version)"

# ── 2. Crear estructura ──────────────────────────────────────

echo "[2/5] Creando estructura..."
mkdir -p "$APP_DIR"

# go.mod
if [ "$WITH_TUI" = "true" ]; then
    cat > "$APP_DIR/go.mod" <<EOF
module ${NOMBRE}

go 1.25.0

require (
	github.com/charmbracelet/bubbles v1.0.0
	github.com/charmbracelet/bubbletea v1.3.10
	github.com/charmbracelet/lipgloss v1.1.0
)

require (
	fn-registry v0.0.0-00010101000000-000000000000
)

replace fn-registry => ${REGISTRY_ROOT}
EOF
else
    cat > "$APP_DIR/go.mod" <<EOF
module ${NOMBRE}

go 1.25.0

require (
	fn-registry v0.0.0-00010101000000-000000000000
)

replace fn-registry => ${REGISTRY_ROOT}
EOF
fi

# ── 3. Archivos Go ───────────────────────────────────────────

echo "[3/5] Escribiendo archivos Go..."

# cmd_version.go — siempre existe
cat > "$APP_DIR/cmd_version.go" <<EOF
package main

import "fmt"

var version = "0.1.0"

func cmdVersion() {
	fmt.Printf("${NOMBRE} %s\n", version)
}
EOF

# cmd_status.go — siempre existe
cat > "$APP_DIR/cmd_status.go" <<EOF
package main

import (
	"fmt"
	"runtime"
)

func cmdStatus() {
	fmt.Printf("app:      ${NOMBRE}\n")
	fmt.Printf("version:  %s\n", version)
	fmt.Printf("go:       %s\n", runtime.Version())
	fmt.Printf("os/arch:  %s/%s\n", runtime.GOOS, runtime.GOARCH)
}
EOF

if [ "$WITH_TUI" = "true" ]; then
    # model.go — Bubbletea BaseModel con spinner y lista
    cat > "$APP_DIR/model.go" <<EOF
package main

import (
	"fmt"

	"github.com/charmbracelet/bubbles/list"
	"github.com/charmbracelet/bubbles/spinner"
	tea "github.com/charmbracelet/bubbletea"
	"github.com/charmbracelet/lipgloss"
)

// --- estilos (dark theme) ---

var (
	titleStyle    = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("#7D56F4"))
	helpStyle     = lipgloss.NewStyle().Foreground(lipgloss.Color("#626262"))
	selectedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#06B6D4"))
)

// --- item de la lista ---

type item struct {
	title, desc string
}

func (i item) Title() string       { return i.title }
func (i item) Description() string { return i.desc }
func (i item) FilterValue() string { return i.title }

// --- modelo raiz ---

type Model struct {
	spinner spinner.Model
	list    list.Model
	status  string
	quit    bool
}

func NewModel() Model {
	items := []list.Item{
		item{title: "Deploy", desc: "Subir codigo al VPS"},
		item{title: "Status", desc: "Ver estado de servicios"},
		item{title: "Logs", desc: "Tail de logs en tiempo real"},
		item{title: "Exit", desc: "Salir"},
	}

	l := list.New(items, list.NewDefaultDelegate(), 0, 0)
	l.Title = "${NOMBRE} — elige una accion"
	l.Styles.Title = titleStyle

	s := spinner.New()
	s.Spinner = spinner.Dot
	s.Style = selectedStyle

	return Model{
		spinner: s,
		list:    l,
		status:  "listo",
	}
}

func (m Model) Init() tea.Cmd {
	return tea.Batch(m.spinner.Tick)
}

func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	var cmds []tea.Cmd

	switch msg := msg.(type) {
	case tea.KeyMsg:
		switch msg.String() {
		case "q", "ctrl+c":
			m.quit = true
			return m, tea.Quit
		case "enter":
			if it, ok := m.list.SelectedItem().(item); ok {
				if it.title == "Exit" {
					m.quit = true
					return m, tea.Quit
				}
				m.status = fmt.Sprintf("seleccionado: %s", it.title)
			}
		}
	case tea.WindowSizeMsg:
		m.list.SetSize(msg.Width, msg.Height-4)
	case spinner.TickMsg:
		var cmd tea.Cmd
		m.spinner, cmd = m.spinner.Update(msg)
		cmds = append(cmds, cmd)
	}

	var cmd tea.Cmd
	m.list, cmd = m.list.Update(msg)
	cmds = append(cmds, cmd)

	return m, tea.Batch(cmds...)
}

func (m Model) View() string {
	if m.quit {
		return "adios!\n"
	}
	return fmt.Sprintf(
		"%s\n\n%s  %s\n%s",
		m.list.View(),
		m.spinner.View(),
		m.status,
		helpStyle.Render("enter: seleccionar · q: salir"),
	)
}
EOF

    # main.go con TUI
    cat > "$APP_DIR/main.go" <<EOF
package main

import (
	"fmt"
	"os"

	tea "github.com/charmbracelet/bubbletea"
)

func main() {
	if len(os.Args) < 2 {
		runTUI()
		return
	}

	switch os.Args[1] {
	case "tui":
		runTUI()
	case "version":
		cmdVersion()
	case "status":
		cmdStatus()
	case "help", "-h", "--help":
		printUsage()
	default:
		fmt.Fprintf(os.Stderr, "comando desconocido: %s\n", os.Args[1])
		printUsage()
		os.Exit(1)
	}
}

func runTUI() {
	p := tea.NewProgram(NewModel(), tea.WithAltScreen())
	if _, err := p.Run(); err != nil {
		fmt.Fprintf(os.Stderr, "tui error: %v\n", err)
		os.Exit(1)
	}
}

func printUsage() {
	fmt.Println(\`${NOMBRE} — CLI tool

Uso:
  ${NOMBRE} [comando]

Sin comando arranca la TUI fullscreen.

Comandos:
  tui       Arranca la TUI fullscreen (default)
  version   Imprime la version
  status    Muestra info del sistema
  help      Muestra esta ayuda\`)
}
EOF
else
    # main.go sin TUI — subcommand routing clasico
    cat > "$APP_DIR/main.go" <<EOF
package main

import (
	"fmt"
	"os"
)

func main() {
	if len(os.Args) < 2 {
		printUsage()
		os.Exit(1)
	}

	switch os.Args[1] {
	case "version":
		cmdVersion()
	case "status":
		cmdStatus()
	case "help", "-h", "--help":
		printUsage()
	default:
		fmt.Fprintf(os.Stderr, "comando desconocido: %s\n", os.Args[1])
		printUsage()
		os.Exit(1)
	}
}

func printUsage() {
	fmt.Println(\`${NOMBRE} — CLI tool

Uso:
  ${NOMBRE} <comando>

Comandos:
  version   Imprime la version
  status    Muestra info del sistema
  help      Muestra esta ayuda\`)
}
EOF
fi

# ── 4. Makefile, .gitignore, app.md ─────────────────────────

echo "[4/5] Escribiendo Makefile, .gitignore, app.md..."

cat > "$APP_DIR/Makefile" <<EOF
.PHONY: build run install test vet clean

BIN=${NOMBRE}

build:
	CGO_ENABLED=1 go build -tags fts5 -o \$(BIN) .

run: build
	./\$(BIN) \$(ARGS)

install: build
	install -m755 \$(BIN) \$(HOME)/.local/bin/\$(BIN)
	@echo "instalado en \$(HOME)/.local/bin/\$(BIN)"

test:
	CGO_ENABLED=1 go test -tags fts5 -v ./...

vet:
	CGO_ENABLED=1 go vet -tags fts5 ./...

clean:
	rm -f \$(BIN)
EOF

cat > "$APP_DIR/.gitignore" <<EOF
# Binario
${NOMBRE}

# IDE
.idea/
.vscode/
*.swp
EOF

if [ "$WITH_TUI" = "true" ]; then
    FRAMEWORK="bubbletea"
    USES_FUNCTIONS='  - new_base_model_go_tui
  - dark_styles_go_tui
  - run_fullscreen_go_tui
  - new_spinner_go_tui
  - new_filtered_list_go_tui'
    TAGS='[cli, tui, bubbletea]'
else
    FRAMEWORK=""
    USES_FUNCTIONS='  []'
    TAGS='[cli]'
fi

cat > "$APP_DIR/app.md" <<EOF
---
name: ${NOMBRE}
lang: go
domain: tools
description: "CLI app generada por init_cli_app."
tags: ${TAGS}
uses_functions:
${USES_FUNCTIONS}
uses_types: []
framework: "${FRAMEWORK}"
entry_point: "main.go"
dir_path: "apps/${NOMBRE}"
---

## Notas

CLI con routing de subcomandos (\`os.Args\` + switch). Sin cobra/urfave —
consistente con las apps del registry.

Ejecutar: \`make run ARGS="version"\` o \`./\${NOMBRE} status\`.
EOF

# ── 5. go mod tidy + go vet ─────────────────────────────────

echo "[5/5] Verificacion..."
(
    cd "$APP_DIR"
    if CGO_ENABLED=1 go mod tidy 2>&1 | tail -5; then
        :
    fi
    if CGO_ENABLED=1 go vet -tags fts5 ./... 2>&1; then
        echo "  go vet OK"
    else
        echo "  WARN: go vet fallo" >&2
    fi
)

echo ""
echo "════════════════════════════════════════════════════════════"
echo "  CLI APP '${NOMBRE}' LISTA"
echo "════════════════════════════════════════════════════════════"
echo ""
echo "  Pasos siguientes:"
echo "    cd apps/${NOMBRE}"
echo "    make build"
if [ "$WITH_TUI" = "true" ]; then
echo "    ./${NOMBRE}         # arranca la TUI fullscreen"
echo "    ./${NOMBRE} version # comando CLI"
else
echo "    ./${NOMBRE} version"
echo "    ./${NOMBRE} status"
fi
echo ""
