package main

import (
	"fmt"
	"strings"

	tea "github.com/charmbracelet/bubbletea"
	"github.com/charmbracelet/lipgloss"
)

var (
	msHiddenStyle  = lipgloss.NewStyle().Background(lipgloss.Color("240")).Foreground(lipgloss.Color("240"))
	msFlagStyle    = lipgloss.NewStyle().Background(lipgloss.Color("240")).Foreground(lipgloss.Color("196")).Bold(true)
	msMineStyle    = lipgloss.NewStyle().Background(lipgloss.Color("52")).Foreground(lipgloss.Color("255")).Bold(true)
	msCursorStyle  = lipgloss.NewStyle().Background(lipgloss.Color("220")).Foreground(lipgloss.Color("16")).Bold(true)
	msNumberColors = map[int]lipgloss.Color{
		1: "39", 2: "34", 3: "196", 4: "129", 5: "94", 6: "37", 7: "255", 8: "245",
	}
)

// MinesweeperModel — TUI поверх MinesweeperGameState.
type MinesweeperModel struct {
	game                 *MinesweeperGameState
	cursor               MinesweeperPos
	width, height, mines int

	message string
	isError bool

	quitting   bool
	backToMenu bool
}

// NewMinesweeperModel создаёт новую партию width x height с mines
// минами.
func NewMinesweeperModel(width, height, mines int) MinesweeperModel {
	return MinesweeperModel{
		game:   NewMinesweeperGame(width, height, mines),
		cursor: MinesweeperPos{Row: height / 2, Col: width / 2},
		width:  width,
		height: height,
		mines:  mines,
	}
}

func (m MinesweeperModel) Init() tea.Cmd { return nil }

func (m *MinesweeperModel) setInfo(key string) {
	m.message = T(key)
	m.isError = false
}

func (m *MinesweeperModel) setError(err error) {
	m.message = T(err.Error())
	m.isError = true
}

func (m MinesweeperModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	keyMsg, ok := msg.(tea.KeyMsg)
	if !ok {
		return m, nil
	}
	return m.handleKey(keyMsg)
}

func (m MinesweeperModel) handleKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
	key := msg.String()

	if key == "ctrl+c" {
		m.quitting = true
		return m, tea.Quit
	}
	if key == "q" {
		m.backToMenu = true
		return m, nil
	}

	if m.game.Result != nil {
		if key == "n" {
			m.game = NewMinesweeperGame(m.width, m.height, m.mines)
			m.cursor = MinesweeperPos{Row: m.height / 2, Col: m.width / 2}
			m.message = ""
			m.isError = false
		}
		return m, nil
	}

	switch key {
	case "up", "k":
		if m.cursor.Row > 0 {
			m.cursor.Row--
		}
	case "down", "j":
		if m.cursor.Row < m.height-1 {
			m.cursor.Row++
		}
	case "left", "h":
		if m.cursor.Col > 0 {
			m.cursor.Col--
		}
	case "right", "l":
		if m.cursor.Col < m.width-1 {
			m.cursor.Col++
		}
	case "enter", " ":
		cell := m.game.Board[m.cursor.Row][m.cursor.Col]
		if cell.Revealed {
			if err := m.game.Chord(m.cursor); err != nil {
				m.setError(err)
				return m, nil
			}
			if m.game.Result != nil && !m.game.Result.Won {
				m.setInfo("minesweeper.msg.boom")
			} else {
				m.setInfo("minesweeper.msg.chorded")
			}
			return m, nil
		}
		if err := m.game.Reveal(m.cursor); err != nil {
			m.setError(err)
			return m, nil
		}
		if m.game.Result != nil && !m.game.Result.Won {
			m.setInfo("minesweeper.msg.boom")
		} else {
			m.setInfo("minesweeper.msg.revealed")
		}
	case "f":
		if err := m.game.ToggleFlag(m.cursor); err != nil {
			m.setError(err)
			return m, nil
		}
		if m.game.Board[m.cursor.Row][m.cursor.Col].Flagged {
			m.setInfo("minesweeper.msg.flagged")
		} else {
			m.setInfo("minesweeper.msg.unflagged")
		}
	}
	return m, nil
}

// --- Отрисовка -----------------------------------------------------

func (m MinesweeperModel) renderCell(pos MinesweeperPos) string {
	cell := m.game.Board[pos.Row][pos.Col]
	isCursor := pos == m.cursor && m.game.Result == nil

	if !cell.Revealed {
		style := msHiddenStyle
		glyph := "▒"
		if cell.Flagged {
			style = msFlagStyle
			glyph = "⚑"
		}
		if isCursor {
			style = msCursorStyle
		}
		return style.Render(" " + glyph + " ")
	}

	if cell.IsMine {
		return msMineStyle.Render(" ✱ ")
	}
	if cell.AdjacentMines == 0 {
		style := lipgloss.NewStyle()
		if isCursor {
			style = msCursorStyle
		}
		return style.Render("   ")
	}
	color := msNumberColors[cell.AdjacentMines]
	style := lipgloss.NewStyle().Foreground(color).Bold(true)
	if isCursor {
		style = msCursorStyle
	}
	return style.Render(fmt.Sprintf(" %d ", cell.AdjacentMines))
}

func (m MinesweeperModel) renderBoard() string {
	var b strings.Builder
	for r := 0; r < m.height; r++ {
		for c := 0; c < m.width; c++ {
			fmt.Fprint(&b, m.renderCell(MinesweeperPos{Row: r, Col: c}))
		}
		fmt.Fprintln(&b)
	}
	return b.String()
}

func (m MinesweeperModel) View() string {
	if m.quitting {
		return T("common.goodbye")
	}

	g := m.game
	var b strings.Builder

	fmt.Fprintln(&b, titleStyle.Render(T("minesweeper.title")))
	fmt.Fprintln(&b)
	remaining := g.MineCount - g.FlagCount
	fmt.Fprintln(&b, Tf("minesweeper.header.mines", remaining))
	fmt.Fprintln(&b)
	fmt.Fprintln(&b, m.renderBoard())
	fmt.Fprintln(&b)

	if g.Result != nil {
		if g.Result.Won {
			fmt.Fprintln(&b, winStyle.Render(T("minesweeper.result.win")))
		} else {
			fmt.Fprintln(&b, errorStyle.Render(T("minesweeper.result.lose")))
		}
		fmt.Fprintln(&b)
		fmt.Fprintln(&b, dimStyle.Render(T("minesweeper.hint.gameover")))
		return b.String()
	}

	fmt.Fprintln(&b, T("minesweeper.hint.play"))

	fmt.Fprintln(&b)
	if m.message != "" {
		if m.isError {
			fmt.Fprintln(&b, errorStyle.Render("! "+m.message))
		} else {
			fmt.Fprintln(&b, infoStyle.Render(m.message))
		}
	}

	return b.String()
}
