package main

import (
	"fmt"
	"strings"
	"time"

	tea "github.com/charmbracelet/bubbletea"
)

// OneOhOneModel — TUI поверх OneOhOneGameState.
type OneOhOneModel struct {
	game     *OneOhOneGameState
	humanIdx int
	bot      OneOhOneBot

	cursor  int
	message string
	isError bool

	quitting   bool
	backToMenu bool
}

// NewOneOhOneModel создаёт новую партию 101 на numPlayers игроков
// (2-6, включая человека) со случайными именами ботов.
func NewOneOhOneModel(numPlayers int) OneOhOneModel {
	if numPlayers < 2 {
		numPlayers = 2
	}
	if numPlayers > 6 {
		numPlayers = 6
	}
	botNames := newOneOhOneBotNames(numPlayers - 1)
	names := append([]string{T("common.you")}, botNames...)

	return OneOhOneModel{
		game:     NewOneOhOneGame(names, 0),
		humanIdx: 0,
		bot:      OneOhOneBot{},
	}
}

func (m OneOhOneModel) Init() tea.Cmd {
	return m.maybeScheduleBot()
}

func (m OneOhOneModel) maybeScheduleBot() tea.Cmd {
	if m.game.Phase != OneOhOnePhasePlay && m.game.Phase != OneOhOnePhaseChooseSuit {
		return nil
	}
	if m.game.CurrentPlayerIdx == m.humanIdx {
		return nil
	}
	return tea.Tick(botMoveDelay, func(time.Time) tea.Msg { return botMoveMsg{} })
}

func (m *OneOhOneModel) resetSelection() {
	hand := m.currentHand()
	if len(hand) == 0 {
		m.cursor = 0
	} else if m.cursor >= len(hand) {
		m.cursor = len(hand) - 1
	}
}

func (m OneOhOneModel) currentHand() []Card {
	if m.game.Phase != OneOhOnePhasePlay {
		return nil
	}
	return m.game.Players[m.game.CurrentPlayerIdx].Hand
}

func (m *OneOhOneModel) setInfo(format string, args ...interface{}) {
	m.message = fmt.Sprintf(format, args...)
	m.isError = false
}

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

func (m OneOhOneModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := msg.(type) {
	case tea.KeyMsg:
		return m.handleKey(msg)
	case botMoveMsg:
		return m.handleBotMove()
	}
	return m, nil
}

func (m OneOhOneModel) handleBotMove() (tea.Model, tea.Cmd) {
	if m.game.Phase != OneOhOnePhasePlay && m.game.Phase != OneOhOnePhaseChooseSuit {
		return m, nil
	}
	idx := m.game.CurrentPlayerIdx
	if idx == m.humanIdx {
		return m, nil
	}
	if err := m.bot.PlayFullTurn(m.game); err != nil {
		m.setError(fmt.Errorf(T("бот %s: %w"), m.game.Players[idx].Name, err))
		return m, nil
	}
	m.setInfo(T("tonk.msg.bot_moved"), m.game.Players[idx].Name)
	if m.game.Phase == OneOhOnePhasePlay && m.game.CurrentPlayerIdx == m.humanIdx {
		m.resetSelection()
	}
	return m, m.maybeScheduleBot()
}

func (m OneOhOneModel) 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.Phase == OneOhOnePhaseRoundOver {
		if key == "n" && !m.game.Result.MatchOver {
			m.game.NextRound()
			m.message = ""
			m.isError = false
			m.resetSelection()
			return m, m.maybeScheduleBot()
		}
		return m, nil
	}

	if m.game.Phase == OneOhOnePhaseChooseSuit {
		if m.game.CurrentPlayerIdx != m.humanIdx {
			return m, nil
		}
		var suit Suit
		switch key {
		case "1":
			suit = Clubs
		case "2":
			suit = Diamonds
		case "3":
			suit = Hearts
		case "4":
			suit = Spades
		default:
			return m, nil
		}
		if err := m.game.ChooseSuit(suit); err != nil {
			m.setError(err)
			return m, nil
		}
		m.setInfo(T("oneohone.msg.suit_chosen"), suitName(suit))
		m.resetSelection()
		return m, m.maybeScheduleBot()
	}

	if m.game.CurrentPlayerIdx != m.humanIdx {
		return m, nil
	}

	hand := m.currentHand()
	switch key {
	case "left", "h":
		if m.cursor > 0 {
			m.cursor--
		}
	case "right", "l":
		if m.cursor < len(hand)-1 {
			m.cursor++
		}
	case "enter", " ":
		if len(hand) == 0 {
			return m, nil
		}
		card := hand[m.cursor]
		if err := m.game.PlayCard(card); err != nil {
			m.setError(err)
			return m, nil
		}
		m.setInfo(T("oneohone.msg.played"), card)
		if m.game.Phase == OneOhOnePhasePlay {
			m.resetSelection()
		}
		return m, m.maybeScheduleBot()
	case "d":
		if err := m.game.Draw(); err != nil {
			m.setError(err)
			return m, nil
		}
		m.setInfo(T("oneohone.msg.drew"))
		if m.game.Phase == OneOhOnePhasePlay {
			m.resetSelection()
		}
		return m, m.maybeScheduleBot()
	}
	return m, nil
}

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

func (m OneOhOneModel) renderHand() string {
	hand := m.currentHand()
	if len(hand) == 0 {
		return dimStyle.Render(T("common.no_cards"))
	}
	return renderCardBoxHand(hand, cursorHighlights(len(hand), m.cursor))
}

func (m OneOhOneModel) renderPlayers() string {
	var b strings.Builder
	for i, p := range m.game.Players {
		marker := "  "
		if m.game.Phase == OneOhOnePhasePlay && i == m.game.CurrentPlayerIdx {
			marker = "> "
		}
		name := p.Name
		status := ""
		if p.Out {
			status = T("oneohone.status.out")
		}
		line := fmt.Sprintf(T("oneohone.player_line"), marker, name, len(p.Hand), p.Score, status)
		if m.game.Phase == OneOhOnePhasePlay && i == m.game.CurrentPlayerIdx {
			line = turnStyle.Render(line)
		}
		fmt.Fprintln(&b, line)
	}
	return strings.TrimRight(b.String(), "\n")
}

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

	var b strings.Builder
	fmt.Fprintln(&b, titleStyle.Render(T("oneohone.title")))
	fmt.Fprintln(&b)
	fmt.Fprintln(&b, m.renderPlayers())
	fmt.Fprintln(&b)
	fmt.Fprintf(&b, T("oneohone.status_line"), renderCard(m.game.topDiscard()), len(m.game.Stock))
	if m.game.PendingEightSuit != nil {
		fmt.Fprintln(&b, errorStyle.Render(Tf("oneohone.pending_eight_line", m.game.PendingEightSuit.String())))
	}
	if m.game.DeclaredSuit != nil {
		fmt.Fprintln(&b, errorStyle.Render(Tf("oneohone.declared_suit_line", m.game.DeclaredSuit.String())))
	}

	if m.game.Phase == OneOhOnePhaseRoundOver {
		fmt.Fprintln(&b, m.renderResult())
		fmt.Fprintln(&b)
		if m.game.Result.MatchOver {
			fmt.Fprintln(&b, dimStyle.Render(T("oneohone.hint.gameover_match")))
		} else {
			fmt.Fprintln(&b, dimStyle.Render(T("oneohone.hint.gameover")))
		}
		return b.String()
	}

	if m.game.Phase == OneOhOnePhaseChooseSuit {
		if m.game.CurrentPlayerIdx == m.humanIdx {
			fmt.Fprintln(&b, T("oneohone.choose_suit_prompt"))
		} else {
			fmt.Fprintf(&b, T("common.thinking"), m.game.Players[m.game.CurrentPlayerIdx].Name)
		}
		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()
	}

	if m.game.CurrentPlayerIdx == m.humanIdx {
		fmt.Fprintln(&b, T("common.your_hand"))
		fmt.Fprintln(&b, m.renderHand())
		fmt.Fprintln(&b)
		fmt.Fprintln(&b, T("oneohone.hint.turn"))
	} else {
		fmt.Fprintf(&b, T("common.thinking"), m.game.Players[m.game.CurrentPlayerIdx].Name)
	}

	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()
}

func (m OneOhOneModel) renderResult() string {
	res := m.game.Result
	var b strings.Builder
	if res.Stalemate {
		fmt.Fprintln(&b, errorStyle.Render(T("oneohone.result.stalemate")))
		return strings.TrimRight(b.String(), "\n")
	}

	winnerName := m.game.Players[res.Winner].Name
	winLine := Tf("oneohone.result.win", winnerName)
	if res.QueenBonus {
		winLine += T("oneohone.result.queen_bonus")
	}
	fmt.Fprintln(&b, winStyle.Render(winLine))
	fmt.Fprintln(&b)

	for i, p := range m.game.Players {
		delta := res.ScoreDeltas[i]
		note := ""
		for _, e := range res.Eliminated {
			if e == i {
				note = T("oneohone.result.eliminated")
			}
		}
		for _, r := range res.Reset {
			if r == i {
				note = T("oneohone.result.reset")
			}
		}
		fmt.Fprintln(&b, fmt.Sprintf(T("oneohone.result.delta_line"), p.Name, delta, p.Score, note))
	}

	if res.MatchOver {
		fmt.Fprintln(&b)
		if res.NoWinner {
			fmt.Fprintln(&b, errorStyle.Render(T("oneohone.result.no_winner")))
		} else {
			fmt.Fprintln(&b, winStyle.Render(Tf("oneohone.result.match_over", m.game.Players[res.MatchWinner].Name)))
		}
	}

	return strings.TrimRight(b.String(), "\n")
}
