package ui

import (
	"fmt"
	"strings"
	"time"

	"termdoku/internal/game"

	"github.com/charmbracelet/lipgloss"
)

func boardString(m Model) string {
	var b strings.Builder
	var dup [9][9]bool
	if m.autoCheck {
		dup = game.DuplicateMap(m.board.Values, m.cursorRow, m.cursorCol)
	}
	var conf [9][9]bool
	if m.autoCheck {
		conf = game.ConflictMap(m.board.Values, m.board.Given)
	}
	cellWidth := lipgloss.Width(m.styles.Cell.Render("0"))

	buildLine := func(left, mid, right string) string {
		seg := strings.Repeat("─", cellWidth)
		var sb strings.Builder
		sb.WriteString(left)
		for c := range 9 {
			sb.WriteString(seg)
			switch c {
			case 8:
				sb.WriteString(right)
			case 2, 5:
				sb.WriteString(mid)
			}
		}
		return sb.String()
	}

	topBorder := m.styles.RowSep.Render(buildLine("╭", "┬", "╮"))
	midBorder := m.styles.RowSep.Render(buildLine("├", "┼", "┤"))
	botBorder := m.styles.RowSep.Render(buildLine("╰", "┴", "╯"))

	b.WriteString(topBorder)
	b.WriteString("\n")

	for r := range 9 {
		b.WriteString(m.styles.ColSep.Render("│"))
		for c := range 9 {
			if c > 0 && c%3 == 0 {
				b.WriteString(m.styles.ColSep.Render("│"))
			}
			cell := m.cellView(r, c, dup[r][c], conf[r][c])
			b.WriteString(cell)
		}
		b.WriteString(m.styles.ColSep.Render("│"))
		b.WriteString("\n")
		if r == 2 || r == 5 {
			b.WriteString(midBorder)
			b.WriteString("\n")
		}
	}
	b.WriteString(botBorder)
	return b.String()
}

func Render(m Model) string {
	if m.showHelp {
		return renderHelpOverlay(m)
	}
	if m.paused {
		return renderPauseScreen(m)
	}

	board := boardString(m)
	status := lipgloss.PlaceHorizontal(46, lipgloss.Center, m.StatusLine())

	// Win animation
	if m.showWinAnim && time.Since(m.winAnimStart) < 2*time.Second {
		winMsg := renderWinAnimation(m)
		return board + "\n\n" + winMsg + "\n" + status
	}

	return board + "\n\n\n" + status
}

func (m Model) cellView(r, c int, isDup, isConf bool) string {
	v := m.board.Values[r][c]
	str := "·"

	// Show notes if cell is empty and has notes
	if v == 0 {
		if notes, ok := m.notes[[2]int{r, c}]; ok && len(notes) > 0 {
			// Show first note as indicator
			str = string('₀' + rune(notes[0])) // subscript numbers
		}
	} else {
		str = string('0' + v)
	}

	style := m.styles.Cell

	if !m.showHelp && !m.paused && !m.completed {
		inSameRow := r == m.cursorRow
		inSameCol := c == m.cursorCol
		inSameBox := (r/3 == m.cursorRow/3) && (c/3 == m.cursorCol/3)

		if !inSameRow && !inSameCol && !inSameBox {
			dimColor := "#555555"
			if m.theme.Name == "light" {
				dimColor = "#d1d5db"
			}
			style = style.Foreground(lipgloss.Color(dimColor))
		} else if inSameRow || inSameCol || inSameBox {
			highlightColor := "#6b7280"
			if m.theme.Name == "light" {
				highlightColor = "#9ca3af"
			}
			if r != m.cursorRow || c != m.cursorCol {
				style = style.Foreground(lipgloss.Color(highlightColor))
			}
		}
	}

	if m.board.Given[r][c] {
		style = m.styles.CellFixed
	}
	if isDup {
		style = m.styles.CellDuplicate
	}
	if isConf {
		style = m.styles.CellConflict
	}
	if r == m.cursorRow && c == m.cursorCol {
		style = m.styles.CellSelected
	}
	if deadline, ok := m.flashes[[2]int{r, c}]; ok {
		if time.Now().Before(deadline) {
			style = style.Bold(true)
		}
	}
	return style.Render(str)
}

func renderPauseScreen(m Model) string {
	pauseMsg := lipgloss.NewStyle().
		Bold(true).
		Foreground(lipgloss.Color("#fbbf24")).
		Render("⏸  PAUSED")

	hint := m.styles.Status.Render("Press 'p' to resume")

	content := pauseMsg + "\n\n" + hint
	box := lipgloss.NewStyle().
		Border(lipgloss.RoundedBorder()).
		BorderForeground(lipgloss.Color("#fbbf24")).
		Padding(2, 4).
		Render(content)

	return lipgloss.Place(80, 24, lipgloss.Center, lipgloss.Center, box)
}

func renderHelpOverlay(m Model) string {
	title := lipgloss.NewStyle().
		Bold(true).
		Foreground(lipgloss.Color(m.theme.Palette.Accent)).
		Render("KEYBOARD SHORTCUTS")

	helpItems := []struct {
		keys string
		desc string
	}{
		{"↑↓←→ / hjkl", "Move cursor"},
		{"1-9", "Enter number"},
		{"0 / Space", "Clear cell"},
		{"n", "Toggle note mode"},
		{"u / Ctrl+Z", "Undo"},
		{"Ctrl+Y / Ctrl+R", "Redo"},
		{"Ctrl+H", "Get hint"},
		{"a", "Toggle auto-check"},
		{"t", "Toggle timer"},
		{"p", "Pause game"},
		{"m", "Main menu"},
		{"?", "Toggle this help"},
		{"q / Esc", "Quit"},
	}

	var helpText strings.Builder
	for _, item := range helpItems {
		key := lipgloss.NewStyle().Foreground(lipgloss.Color("#60a5fa")).Bold(true).Render(item.keys)
		desc := m.styles.Status.Render(item.desc)
		helpText.WriteString(fmt.Sprintf("  %-25s %s\n", key, desc))
	}

	content := title + "\n\n" + helpText.String() + "\n" +
		m.styles.Status.Render("Press '?' again to close")

	box := lipgloss.NewStyle().
		Border(lipgloss.RoundedBorder()).
		BorderForeground(lipgloss.Color(m.theme.Palette.Accent)).
		Padding(1, 2).
		Render(content)

	return lipgloss.Place(80, 30, lipgloss.Center, lipgloss.Center, box)
}

func renderWinAnimation(m Model) string {
	elapsed := time.Since(m.winAnimStart).Milliseconds()

	confetti := []string{"✨", "🎉", "🎊", "⭐", "💫", "🌟", "✦", "★"}
	animPhase := int(elapsed / 150)

	var confettiLine strings.Builder
	for i := 0; i < 20; i++ {
		if (i+animPhase)%3 == 0 {
			symbol := confetti[(i+animPhase)%len(confetti)]
			confettiLine.WriteString(symbol)
		} else {
			confettiLine.WriteString(" ")
		}
	}

	colors := []string{"#10b981", "#3b82f6", "#8b5cf6", "#f59e0b", "#ef4444"}
	colorIdx := (animPhase / 2) % len(colors)

	mainMsg := "🏆  PUZZLE COMPLETE!  🏆"
	styledMsg := lipgloss.NewStyle().
		Bold(true).
		Foreground(lipgloss.Color(colors[colorIdx])).
		Render(mainMsg)

	return confettiLine.String() + "\n" + styledMsg + "\n" + confettiLine.String()
}
