package tui

import (
	"fmt"
	"strings"

	tea "github.com/charmbracelet/bubbletea"
	"github.com/yeho/klp/internal/database"
)

type Model struct {
	entries  []*database.Entry
	db       *database.Database
	cursor   int
	selected *database.Entry
	title    string
	quitting bool
	width    int
	height   int
}

func New(entries []*database.Entry, db *database.Database, title string) Model {
	return Model{
		entries: entries,
		db:      db,
		cursor:  0,
		title:   title,
	}
}

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

func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := msg.(type) {
	case tea.KeyMsg:
		switch msg.String() {
		case "ctrl+c", "q", "esc":
			m.quitting = true
			return m, tea.Quit

		case "enter":
			if len(m.entries) > 0 && m.cursor < len(m.entries) {
				m.selected = m.entries[m.cursor]
			}
			return m, tea.Quit

		case "up", "k":
			if m.cursor > 0 {
				m.cursor--
			}

		case "down", "j":
			if m.cursor < len(m.entries)-1 {
				m.cursor++
			}

		case "home", "g":
			m.cursor = 0

		case "end", "G":
			m.cursor = len(m.entries) - 1

		case "d":
			if len(m.entries) > 0 && m.cursor < len(m.entries) && m.db != nil {
				entry := m.entries[m.cursor]
				if err := m.db.Delete(entry.ID); err == nil {
					// Remove from local list
					m.entries = append(m.entries[:m.cursor], m.entries[m.cursor+1:]...)
					// Adjust cursor if needed
					if m.cursor >= len(m.entries) && m.cursor > 0 {
						m.cursor--
					}
					// Update title with new count
					m.title = fmt.Sprintf("Clipboard History (%d entries)", len(m.entries))
				}
			}
		}

	case tea.WindowSizeMsg:
		m.width = msg.Width
		m.height = msg.Height
	}

	return m, nil
}

func (m Model) View() string {
	if len(m.entries) == 0 {
		return NoResultsStyle.Render("No clipboard entries found")
	}

	var b strings.Builder

	// Title
	b.WriteString(TitleStyle.Render(m.title))
	b.WriteString("\n")

	// Calculate visible window
	maxVisible := 10
	if m.height > 0 {
		maxVisible = m.height - 6 // Account for title, help, margins
		if maxVisible < 5 {
			maxVisible = 5
		}
	}

	start := 0
	end := len(m.entries)
	if len(m.entries) > maxVisible {
		start = m.cursor - maxVisible/2
		if start < 0 {
			start = 0
		}
		end = start + maxVisible
		if end > len(m.entries) {
			end = len(m.entries)
			start = end - maxVisible
			if start < 0 {
				start = 0
			}
		}
	}

	// Calculate max content width
	maxContentWidth := 60
	if m.width > 0 {
		// Reserve space for cursor, ID, datetime, and margins
		maxContentWidth = m.width - 30
		if maxContentWidth < 20 {
			maxContentWidth = 20
		}
	}

	for i := start; i < end; i++ {
		entry := m.entries[i]
		isSelected := i == m.cursor

		// Cursor indicator
		cursor := "  "
		if isSelected {
			cursor = CursorStyle.Render("> ")
		}

		// ID
		var id string
		if isSelected {
			id = IDStyleSelected.Render(entry.ID)
		} else {
			id = IDStyle.Render(entry.ID)
		}

		// DateTime
		dateStr := entry.DateTime.Format("01/02 15:04")
		var dateTime string
		if isSelected {
			dateTime = DateTimeStyleSelected.Render(dateStr)
		} else {
			dateTime = DateTimeStyle.Render(dateStr)
		}

		// Content preview (truncate and clean)
		preview := cleanPreview(entry.Value, maxContentWidth)
		var content string
		if isSelected {
			content = ContentStyleSelected.Render(preview)
		} else {
			content = ContentStyle.Render(preview)
		}

		line := fmt.Sprintf("%s%s %s  %s", cursor, id, dateTime, content)
		b.WriteString(line)
		b.WriteString("\n")
	}

	// Scroll indicator
	if len(m.entries) > maxVisible {
		scrollInfo := fmt.Sprintf("(%d-%d of %d)", start+1, end, len(m.entries))
		b.WriteString(DateTimeStyle.Render(scrollInfo))
		b.WriteString("\n")
	}

	// Help
	help := "\n  j/k up/down  enter select  d delete  q quit"
	b.WriteString(HelpStyle.Render(help))

	return b.String()
}

func cleanPreview(s string, maxLen int) string {
	// Replace newlines with spaces
	result := strings.ReplaceAll(s, "\n", " ")
	result = strings.ReplaceAll(result, "\r", "")
	result = strings.ReplaceAll(result, "\t", " ")

	// Collapse multiple spaces
	for strings.Contains(result, "  ") {
		result = strings.ReplaceAll(result, "  ", " ")
	}

	result = strings.TrimSpace(result)

	// Truncate
	if len(result) > maxLen {
		result = result[:maxLen-3] + "..."
	}

	return result
}

func (m Model) Selected() *database.Entry {
	return m.selected
}

func (m Model) Quitting() bool {
	return m.quitting
}

func Run(entries []*database.Entry, db *database.Database, title string) (*database.Entry, error) {
	model := New(entries, db, title)
	p := tea.NewProgram(model)

	finalModel, err := p.Run()
	if err != nil {
		return nil, err
	}

	m := finalModel.(Model)
	return m.Selected(), nil
}
