package cli

import (
	"fmt"
	"math/rand"
	"regexp"
	"strings"

	"github.com/charmbracelet/lipgloss"
	"github.com/diillson/chatcli/i18n"
	"github.com/diillson/chatcli/version"
	"github.com/mattn/go-runewidth"
)

// Dicas agora contêm as chaves de tradução.
var tipKeys = []string{ // <-- 2. ALTERADO DE 'tips' PARA 'tipKeys'
	"tip.add_file",
	"tip.git_context",
	"tip.exec_command",
	"tip.switch_provider",
	"tip.new_session",
	"tip.view_config",
	"tip.cancel_request",
	"tip.agent_mode",
	"tip.agent_toggle_view",
	"tip.agent_output_actions",
	"tip.agent_last_result",
}

// screenWidth is the anchor width used to center welcome-screen
// content (logo, tip box, active-model card, footer). It is a fixed
// 87 columns by design: anchoring at the terminal width left the
// banner pushed far to the right on wide terminals and read as
// awkward — the welcome reads more naturally hugging the left edge
// like the rest of the prompt does. Keeping a const here means tip
// box and model card stay centered relative to the logo regardless
// of how the user has sized their terminal.
const screenWidth = 87

// printLogo exibe o novo logo do ChatCLI em ASCII art, centralizado
// num bloco virtual de 80 colunas (mesma largura usada antes da
// refatoração de envelope). Esse bloco fica na borda esquerda do
// terminal, por preferência do usuário — uma centralização no
// terminal inteiro empurra o banner pra direita em telas largas.
func printLogo() {
	logo := `
           ██████╗ ██╗  ██╗ █████╗ ████████╗ ██████╗██╗     ██╗
          ██╔════╝ ██║  ██║██╔══██╗╚══██╔══╝██╔════╝██║     ██║
          ██║      ███████║███████║   ██║   ██║     ██║     ██║
          ██║      ██╔══██║██╔══██║   ██║   ██║     ██║     ██║
          ╚██████╗ ██║  ██║██║  ██║   ██║   ╚██████╗███████╗██║
           ╚═════╝ ╚═╝  ╚═╝╚═╝  ╚═╝   ╚═╝    ╚═════╝╚══════╝╚═╝
        `

	coloredLogo := strings.ReplaceAll(logo, "█", colorize("█", ColorLime))
	coloredLogo = strings.ReplaceAll(coloredLogo, "╗", colorize("╗", ColorGray))
	coloredLogo = strings.ReplaceAll(coloredLogo, "╔", colorize("╔", ColorGray))
	coloredLogo = strings.ReplaceAll(coloredLogo, "╚", colorize("╚", ColorGray))
	coloredLogo = strings.ReplaceAll(coloredLogo, "╝", colorize("╝", ColorGray))
	coloredLogo = strings.ReplaceAll(coloredLogo, "═", colorize("═", ColorGray))
	coloredLogo = strings.ReplaceAll(coloredLogo, "║", colorize("║", ColorGray))

	width := 80
	for _, line := range strings.Split(coloredLogo, "\n") {
		if strings.TrimSpace(line) == "" {
			continue
		}
		// calcula padding
		visible := visibleLen(line)
		if visible < width {
			left := (width - visible) / 2
			fmt.Println(strings.Repeat(" ", left) + line)
		} else {
			fmt.Println(line)
		}
	}
}

// --- util: ANSI / largura visível (conta runas, ignora cores) ---
var ansiRe = regexp.MustCompile(`\x1b\[[0-9;]*m`)

func removeColorCodes(s string) string {
	return ansiRe.ReplaceAllString(s, "")
}

func visibleLen(s string) int {
	return runewidth.StringWidth(removeColorCodes(s))
}

// --- quebra preservando códigos ANSI ---
func wrapStringWithColor(text string, maxWidth int) []string {
	if maxWidth <= 0 {
		return []string{text}
	}
	words := strings.Fields(text)
	if len(words) == 0 {
		return nil
	}

	var lines []string
	var b strings.Builder
	curr := 0

	for _, w := range words {
		wlen := visibleLen(w)

		// se não cabe na linha atual, pula pra próxima
		if curr > 0 && curr+1+wlen > maxWidth {
			lines = append(lines, b.String())
			b.Reset()
			curr = 0
		}
		if curr > 0 {
			b.WriteByte(' ')
			curr++
		}
		b.WriteString(w)
		curr += wlen
	}
	if b.Len() > 0 {
		lines = append(lines, b.String())
	}
	return lines
}

// tipBoxBorderStyle is the rounded gray border used for the welcome
// tip box and the active-model card. Defined once so future palette
// changes touch one spot. lipgloss.Color("8") maps to the terminal's
// "bright black" ANSI slot — same color the rest of the welcome
// screen uses for chrome, so it stays themable.
var tipBoxBorderStyle = lipgloss.NewStyle().
	Border(lipgloss.RoundedBorder()).
	BorderForeground(lipgloss.Color("8"))

// printTipBox renders a centered "Did you know?" tip card. lipgloss
// owns the border drawing and width math so a future change to the
// box style (different border, padding tweak, color) is a one-liner
// instead of a fistful of strings.Repeat calls.
func printTipBox() {
	tipKey := tipKeys[rand.Intn(len(tipKeys))] //#nosec G404 -- non-cryptographic: picks a welcome-screen tip
	tip := i18n.T(tipKey)
	title := i18n.T("welcome.tip.title")

	// Inner content width = card width − 2 borders − 2 of padding.
	innerWidth := screenWidth - 4

	// Title line: " ─── Did you know? ─── " centered above the body.
	// We bake the title into the body so it appears INSIDE the box at
	// the top, separated from the tip by a blank line. lipgloss's
	// default border doesn't natively accept a "title within the top
	// edge" yet, so this is the cleanest workaround.
	titleLine := lipgloss.NewStyle().
		Width(innerWidth).
		Align(lipgloss.Center).
		Bold(true).
		Foreground(lipgloss.Color("15")).
		Render(title)

	// Wrap the tip body to the inner width using the existing visible-
	// length-aware helper. lipgloss's word-wrap is also ANSI-aware but
	// our wrapStringWithColor already handles the edge cases (color
	// codes mid-word) so we reuse it.
	wrapped := strings.Join(wrapStringWithColor(tip, innerWidth), "\n")
	body := lipgloss.NewStyle().
		Width(innerWidth).
		Align(lipgloss.Center).
		Foreground(lipgloss.Color("7")).
		Render(wrapped)

	card := tipBoxBorderStyle.
		Padding(1, 1).
		Render(titleLine + "\n\n" + body)

	// Center the card on the configured screenWidth so the overall
	// welcome layout stays balanced.
	fmt.Println(lipgloss.PlaceHorizontal(screenWidth, lipgloss.Center, card))
}

// PrintWelcomeScreen exibe a tela de boas-vindas completa e traduzida.
//
// Layout (todos centrados em screenWidth):
//
//	<ASCII logo>
//	v1.2.3 · commit abc123
//	╭── Did you know? ──╮
//	│   <tip>           │
//	╰───────────────────╯
//	╭── Active model ────╮
//	│ ◆ name · provider │
//	╰────────────────────╯
//	/help · /exit · /switch
//
// The shift to centered + boxed Active-model block came with PR3:
// before it was left-aligned plain text while everything else was
// centered, which read as "two screens spliced together".
func (cli *ChatCLI) PrintWelcomeScreen() {
	printLogo()

	v, c, _ := version.GetBuildInfo()
	if v != "" && v != "dev" && v != "unknown" {
		versionStr := i18n.T("version.label", v, c)
		fmt.Println(lipgloss.PlaceHorizontal(screenWidth, lipgloss.Center,
			colorize(versionStr, ColorGray)))
		fmt.Println()
	}

	printTipBox()

	// Active-model card. Same border style as the tip box so the two
	// sit visually balanced on the screen. Falls back to a "no model"
	// state with a hint when no provider is wired up.
	var modelLine string
	if cli.Client != nil {
		modelLine = lipgloss.JoinHorizontal(lipgloss.Top,
			colorize("◆ ", ColorLime),
			colorize(cli.Client.GetModelName(), ColorLime+ColorBold),
			colorize(" · ", ColorGray),
			colorize(cli.Provider, ColorGray),
		)
	} else {
		modelLine = lipgloss.JoinVertical(lipgloss.Left,
			colorize("◆ "+i18n.T("welcome.current_model", "(none)", "No provider"), ColorYellow),
			colorize(i18n.T("welcome.auth_hint"), ColorGray),
		)
	}
	modelCard := tipBoxBorderStyle.
		Padding(0, 2).
		Render(modelLine)
	fmt.Println(lipgloss.PlaceHorizontal(screenWidth, lipgloss.Center, modelCard))

	// Footer of quick commands, centered to match the rest of the
	// layout. Plain Bullet (·) instead of the heavier "  •  " for a
	// lighter look that pairs better with the lipgloss-rendered cards.
	footer := lipgloss.JoinHorizontal(lipgloss.Top,
		colorize(i18n.T("welcome.footer.help.cmd"), ColorGreen),
		colorize(" "+i18n.T("welcome.footer.help.desc"), ColorGray),
		colorize("  ·  ", ColorGray),
		colorize(i18n.T("welcome.footer.exit.cmd"), ColorGreen),
		colorize(" "+i18n.T("welcome.footer.exit.desc"), ColorGray),
		colorize("  ·  ", ColorGray),
		colorize(i18n.T("welcome.footer.switch_model.cmd"), ColorGreen),
		colorize(" "+i18n.T("welcome.footer.switch_model.desc"), ColorGray),
	)
	fmt.Println()
	fmt.Println(lipgloss.PlaceHorizontal(screenWidth, lipgloss.Center, footer))
	fmt.Println()
}
