package tui

import (
	"fmt"
	"get-container/cmd/hytop/backend"
	"maps"
	"regexp"
	"strconv"
	"strings"

	"github.com/charmbracelet/bubbles/progress"
	tea "github.com/charmbracelet/bubbletea"
	"github.com/charmbracelet/lipgloss"
	"github.com/muesli/termenv"
)

type ModelDCUInfo struct {
	DCUNum        int                     // dcu数量
	width, height int                     // 终端的尺寸
	info          map[int]backend.DCUInfo // dcu相关信息
	pro           progress.Model          // 进度条
	proWidth      int                     // 进度条宽度
}

const (
	TopLine    = `╞═══════════════════════════════╪══════════════════════╪══════════════════════╪`
	MiddleLine = `├───────────────────────────────┼──────────────────────┼──────────────────────┼`
	BottomLine = `╞═══════════════════════════════╧══════════════════════╧══════════════════════╪`

	OtherWidth       = 8
	StaticWidth      = 79 // 固定表格的宽度
	ProgressMinWidth = 15 // 进度条最小宽度
)

var (
	ReDCUName = regexp.MustCompile(`(?i)^[A-Z0-9-_]*`)
)

func (m *ModelDCUInfo) Init() tea.Cmd {
	if m.width < StaticWidth+ProgressMinWidth {
		return tea.Quit
	}
	m.proWidth = ProgressMinWidth
	if m.width > StaticWidth+ProgressMinWidth+OtherWidth {
		m.proWidth = m.width - OtherWidth - StaticWidth
	}
	m.pro = progress.New(progress.WithColorProfile(termenv.TrueColor), progress.WithGradient("#0000ffff", "#ff0000ff"), progress.WithWidth(m.proWidth))
	return nil
}

func (m *ModelDCUInfo) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := inputMsg.(type) {
	case *ModelMsg:
		clear(m.info)
		maps.Copy(m.info, msg.DCUInfo)
		return m, nil
	}
	return m, nil
}

func (m *ModelDCUInfo) View() string {
	lineWidth := 0
	l := len(m.info)
	strBuilder := strings.Builder{}
	infos := make([]string, l)
	for i := range l {
		ii := m.info[i]
		strBuilder.WriteString(myBorder.Left)
		strBuilder.WriteByte(' ')
		strBuilder.WriteString(FormatStr(strconv.Itoa(ii.Id), 4, lipgloss.Left))
		strBuilder.WriteByte(' ')
		strBuilder.WriteString(FormatStr(ReDCUName.FindString(ii.Name), 8, lipgloss.Left))
		strBuilder.WriteByte(' ')
		strBuilder.WriteString(FormatStr(ii.PerformanceLevel, 15, lipgloss.Right))
		strBuilder.WriteByte(' ')
		strBuilder.WriteString(myBorder.Left)
		strBuilder.WriteByte(' ')
		strBuilder.WriteString(FormatStr(ii.BusId, 13, lipgloss.Left))
		strBuilder.WriteByte(' ')
		strBuilder.WriteString(FormatStr("Off", 6, lipgloss.Right))
		strBuilder.WriteByte(' ')
		strBuilder.WriteString(myBorder.Left)
		strBuilder.WriteByte(' ')
		if ii.Mig {
			strBuilder.WriteString(FormatStr("On", 16, lipgloss.Left))
		} else {
			strBuilder.WriteString(FormatStr("Off", 16, lipgloss.Left))
		}
		strBuilder.WriteByte(' ')
		if ii.Ecc {
			strBuilder.WriteString(FormatStr("On", 3, lipgloss.Right))
		} else {
			strBuilder.WriteString(FormatStr("Off", 3, lipgloss.Right))
		}
		strBuilder.WriteByte(' ')
		strBuilder.WriteString(myBorder.Left)
		strBuilder.WriteString(" DCU: ")
		strBuilder.WriteString(m.pro.ViewAs(float64(ii.DCUUTil) / 100))
		strBuilder.WriteByte(' ')
		strBuilder.WriteString(myBorder.Left)
		strBuilder.WriteByte('\n')
		strBuilder.WriteString(myBorder.Left)
		strBuilder.WriteByte(' ')
		strBuilder.WriteString(FormatStr(ii.Fan, 4, lipgloss.Left))
		strBuilder.WriteByte(' ')
		strBuilder.WriteString(FormatStr(fmt.Sprintf("%.1fC", ii.Temp), 6, lipgloss.Left))
		strBuilder.WriteByte(' ')
		// 18
		strBuilder.WriteString(FormatStr(fmt.Sprintf("%.1fW / %.1fW", ii.PwrAvg, ii.PwrCap), 17, lipgloss.Right))
		strBuilder.WriteByte(' ')
		strBuilder.WriteString(myBorder.Left)
		strBuilder.WriteByte(' ')
		// 20
		strBuilder.WriteString(FormatStr(fmt.Sprintf("%dMiB / %dMiB", ii.MemUsed, ii.MemTotal), 20, lipgloss.Right))
		strBuilder.WriteByte(' ')
		strBuilder.WriteString(myBorder.Left)
		strBuilder.WriteByte(' ')
		strBuilder.WriteString(FormatStr(fmt.Sprintf("%.1f%%", ii.DCUUTil), 6, lipgloss.Left))
		strBuilder.WriteByte(' ')
		strBuilder.WriteString(FormatStr(ii.PwrMode, 13, lipgloss.Right))
		strBuilder.WriteByte(' ')
		strBuilder.WriteString(myBorder.Left)
		strBuilder.WriteString(" Mem: ")
		strBuilder.WriteString(m.pro.ViewAs(float64(ii.MemUsedPerent) / 100))
		strBuilder.WriteByte(' ')
		strBuilder.WriteString(myBorder.Left)
		infos[i] = strBuilder.String()
		strBuilder.Reset()
	}
	if len(infos) > 0 {
		lineWidth = lipgloss.Width(infos[0])
	}
	subLen := lineWidth - StaticWidth - 1
	if subLen <= 0 {
		subLen = 0
	}
	top := TopLine + strings.Repeat("═", subLen) + "╕\n"
	middle := "\n" + MiddleLine + strings.Repeat("─", subLen) + "┤\n"
	bottom := "\n" + BottomLine + strings.Repeat("═", subLen) + "╡\n"
	return top + strings.Join(infos, middle) + bottom
}
