package metricstui

import (
	"fmt"

	"github.com/charmbracelet/bubbles/list"
	tea "github.com/charmbracelet/bubbletea"
)

const (
	defaultTUIWidth  = 100
	defaultTUIHeight = 28
	minListWidth     = 18
	maxListWidth     = 40
	minChartWidth    = 16
	minChartHeight   = 6
)

type rangeModel struct {
	response *QueryRangeResponse
	list     list.Model
	width    int
	height   int
	quitting bool
}

type seriesListItem struct {
	series QueryRangeSeries
}

func (i seriesListItem) FilterValue() string {
	return i.series.Label
}

func (i seriesListItem) Title() string {
	return i.series.Label
}

func (i seriesListItem) Description() string {
	if i.series.InvalidSamples > 0 {
		return fmt.Sprintf("%d samples (%d skipped)", len(i.series.Samples), i.series.InvalidSamples)
	}
	return fmt.Sprintf("%d samples", len(i.series.Samples))
}

func newRangeModel(response *QueryRangeResponse) rangeModel {
	if response == nil {
		response = &QueryRangeResponse{}
	}

	items := make([]list.Item, 0, len(response.Series))
	for _, series := range response.Series {
		items = append(items, seriesListItem{series: series})
	}

	delegate := list.NewDefaultDelegate()
	delegate.ShowDescription = false
	delegate.SetSpacing(0)

	seriesList := list.New(items, delegate, minListWidth, defaultTUIHeight-2)
	seriesList.Title = "Series"
	seriesList.SetShowTitle(false)
	seriesList.SetShowFilter(false)
	seriesList.SetFilteringEnabled(false)
	seriesList.SetShowHelp(false)
	seriesList.SetShowStatusBar(false)
	seriesList.SetShowPagination(false)
	seriesList.DisableQuitKeybindings()

	model := rangeModel{
		response: response,
		list:     seriesList,
		width:    defaultTUIWidth,
		height:   defaultTUIHeight,
	}
	model.resize(defaultTUIWidth, defaultTUIHeight)
	return model
}

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

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

	if m.isEmpty() {
		return m, nil
	}

	var cmd tea.Cmd
	m.list, cmd = m.list.Update(msg)
	return m, cmd
}

func (m rangeModel) View() string {
	if m.isEmpty() {
		return renderEmptyStateView(m.width, m.height)
	}
	return renderRangeView(m)
}

func (m *rangeModel) resize(width, height int) {
	m.width = maxInt(width, 1)
	m.height = maxInt(height, 1)

	listWidth, listHeight := calculateListSize(m.width, m.height)
	m.list.SetSize(listWidth, listHeight)
}

func (m rangeModel) isEmpty() bool {
	return m.response == nil || len(m.response.Series) == 0
}

func (m rangeModel) selectedSeries() (QueryRangeSeries, bool) {
	item, ok := m.list.SelectedItem().(seriesListItem)
	if !ok {
		return QueryRangeSeries{}, false
	}
	return item.series, true
}

func calculateListSize(width, height int) (int, int) {
	if width <= 0 {
		width = 1
	}
	if height <= 0 {
		height = 1
	}

	if useStackedLayout(width) {
		return maxInt(width-2, 1), maxInt(minInt(height/3, height-2), 1)
	}

	listWidth := width / 3
	if listWidth < minListWidth {
		listWidth = minListWidth
	}
	if listWidth > maxListWidth {
		listWidth = maxListWidth
	}
	if listWidth > width-2 {
		listWidth = maxInt(width-2, 1)
	}

	return listWidth, maxInt(height-2, 1)
}

func useStackedLayout(width int) bool {
	return width < 72
}

func minInt(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func maxInt(a, b int) int {
	if a > b {
		return a
	}
	return b
}
