package tui

import (
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/NimbleMarkets/ntcharts/canvas/runes"
	tchart "github.com/NimbleMarkets/ntcharts/linechart/timeserieslinechart"
	tea "github.com/charmbracelet/bubbletea"
	"github.com/charmbracelet/lipgloss"
	zone "github.com/lrstanley/bubblezone"
)

const (
	A = "├"
)

var (
	axisFStyle = lipgloss.NewStyle().Inline(true).Foreground(lipgloss.Color("#707070ff"))
)

// genXAxis 生成X轴，参数l是x轴的长度
func genXAxis(l int) string {
	t60 := l / 30
	t30 := l >= 18
	var result string
	if t30 {
		result = A + strings.Repeat("─", 14)
		result = axisFStyle.Render("30s") + result
	} else {
		return strings.Repeat("─", l)
	}
	// 长度不超过33
	if l < 33 {
		return strings.Repeat("─", l-18) + result
	}
	for i := 1; i <= t60+1; i++ {
		timeStr := strconv.Itoa(i*60) + "s"
		timeStrLen := len(timeStr)
		timeStr = axisFStyle.Render(timeStr)
		targetLen := timeStrLen + i*30
		if l < targetLen {
			// 不渲染标记，仅增加轴长度
			result = strings.Repeat("─", l-lipgloss.Width(result)) + result
			break
		}
		// 渲染标记
		result = timeStr + A + strings.Repeat("─", targetLen-lipgloss.Width(result)-timeStrLen-1) + result
	}
	return result
}

// MyTimeChartMsg 时间流表消息，用于插入数据
type MyTimeChartMsg struct {
	point tchart.TimePoint
}

// MyTimeChart 特化的时间流表，时间区域就是宽度的2倍，单位是秒
type MyTimeChart struct {
	chart         *tchart.Model      // 原始图表
	zM            *zone.Manager      // 区域管理
	points        []tchart.TimePoint // 数据点
	width, height int                // 图表的高度和宽度
	max, min      float64            // y轴的最值
}

func New(width, height int, vmin, vmax float64) *MyTimeChart {
	result := MyTimeChart{}
	result.max = vmax
	result.min = vmin
	result.width = width
	result.height = height
	zoneManager := zone.New()
	result.zM = zoneManager
	result.points = make([]tchart.TimePoint, 0)
	// 准备数据，数据间隔为1秒
	now := time.Now()
	for i := result.width * 2; i >= 0; i-- {
		result.points = append(result.points, tchart.TimePoint{Time: now.Add(-time.Duration(i) * time.Second), Value: vmin})
	}
	s := tchart.New(width, height,
		tchart.WithLineStyle(runes.ThinLineStyle),
		tchart.WithZoneManager(zoneManager),
		tchart.WithYRange(vmin, vmax),
		tchart.WithTimeSeries(result.points),
		tchart.WithXYSteps(0, 0),
	)
	result.chart = &s
	return &result
}

func (m *MyTimeChart) PutPoint(timePoint tchart.TimePoint) {
	m.points = append(m.points, timePoint)
	// 排序
	sort.Slice(m.points, func(i, j int) bool {
		return m.points[i].Time.Before(m.points[j].Time)
	})
	// 剔除不要的数据
	threshold := time.Now().Add(time.Second * time.Duration(-2*m.width))
	targetIndex := 0
	for i, p := range m.points {
		if !p.Time.Before(threshold) {
			targetIndex = i
			break
		}
	}
	points := append(make([]tchart.TimePoint, 0), m.points[targetIndex:]...)
	m.points = points
	// 更新chart
	s := tchart.New(m.width, m.height,
		tchart.WithLineStyle(runes.ThinLineStyle),
		tchart.WithZoneManager(m.zM),
		tchart.WithYRange(m.min, m.max),
		tchart.WithTimeSeries(m.points),
		tchart.WithXYSteps(0, 0),
	)
	m.chart = &s
}

func (m *MyTimeChart) Init() tea.Cmd {
	m.chart.DrawXYAxisAndLabel()
	m.chart.DrawBraille()
	return nil
}

func (m *MyTimeChart) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := inputMsg.(type) {
	case MyTimeChartMsg:
		m.PutPoint(msg.point)
		return m, nil
	}
	return m, nil
}

func (m *MyTimeChart) View() string {
	return m.zM.Scan(m.chart.View())
}
