package tui

import (
	"get-container/cmd/hytop/backend"
	"get-container/gpu"
	"get-container/utils"
	"time"

	tea "github.com/charmbracelet/bubbletea"
	"github.com/charmbracelet/lipgloss"
)

const (
	DCUTopVersion = "1.0.0"
)

// ModelMsg 模型信息，在父组件和各个子组件间共享信息
type ModelMsg struct {
	t          time.Time          // 当前时间
	index      uint64             // update次数
	Version    *gpu.HYVersionInfo // gpu版本相关信息
	MyVersion  string
	DCUInfo    map[int]backend.DCUInfo          // DCU全量信息
	DCUPidInfo map[int][]backend.DCUProcessInfo // 使用dcu的进程信息
	systemInfo *utils.SysInfo                   // 系统信息
}

type TickMsg time.Time

// ModelMain tui主模型类
type ModelMain struct {
	width, height int // 终端尺寸
	Header        *ModelHeader
	DCUInfo       *ModelDCUInfo
	SysLoad       *ModelSysLoad
	ProcessInfo   *ModelProcessInfo
	index         uint64    // 记录update次数的值
	modelMsg      *ModelMsg // 记录模型信息
}

func NewModelMain(width, height int) ModelMain {
	result := ModelMain{}
	result.width = width
	result.height = height
	result.Header = &ModelHeader{}
	result.DCUInfo = &ModelDCUInfo{width: width, height: height, info: make(map[int]backend.DCUInfo)}
	result.SysLoad = NewModelSysLoad(width)
	result.ProcessInfo = NewModelProcessInfo(width)
	return result
}

func tickCmd() tea.Cmd {
	return tea.Every(time.Second, func(t time.Time) tea.Msg {
		return TickMsg(t)
	})
}

func sendMsgCmd(modelMsg *ModelMsg) tea.Cmd {
	return func() tea.Msg {
		return *modelMsg
	}
}

// Init 初始化信息
func (m *ModelMain) Init() tea.Cmd {
	modelMsg := ModelMsg{}
	if err := initModelInfo(&modelMsg); err != nil {
		return tea.Quit
	}
	cmds := make([]tea.Cmd, 0)
	if c := m.Header.Init(); c != nil {
		cmds = append(cmds, c)
	}
	m.DCUInfo.DCUNum = len(modelMsg.DCUInfo)
	if c := m.DCUInfo.Init(); c != nil {
		cmds = append(cmds, c)
	}

	if c := m.SysLoad.Init(); c != nil {
		cmds = append(cmds, c)
	}
	if c := m.ProcessInfo.Init(); c != nil {
		cmds = append(cmds, c)
	}
	m.modelMsg = &modelMsg
	// 将调用初始化方法
	cmds = append(cmds, tickCmd(), sendMsgCmd(&modelMsg))
	return tea.Batch(cmds...)
}

func (m *ModelMain) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := inputMsg.(type) {
	case tea.KeyMsg: // 键盘事件
		switch msg.String() {
		case "ctrl+c", "q":
			return m, tea.Quit
		}
	case TickMsg: // 定时事件
		m.index++
		updateModelInfo(m.modelMsg, m.index, time.Time(msg))
		header, _ := m.Header.Update(m.modelMsg)
		dcuInfo, _ := m.DCUInfo.Update(m.modelMsg)
		sysLoad, _ := m.SysLoad.Update(m.modelMsg)
		pidinfo, _ := m.ProcessInfo.Update(m.modelMsg)
		m.Header = header.(*ModelHeader)
		m.DCUInfo = dcuInfo.(*ModelDCUInfo)
		m.SysLoad = sysLoad.(*ModelSysLoad)
		m.ProcessInfo = pidinfo.(*ModelProcessInfo)
		return m, tickCmd()
	case ModelMsg: // 初始化
		header, _ := m.Header.Update(m.modelMsg)
		dcuInfo, _ := m.DCUInfo.Update(m.modelMsg)
		sysLoad, _ := m.SysLoad.Update(m.modelMsg)
		pidinfo, _ := m.ProcessInfo.Update(m.modelMsg)
		m.Header = header.(*ModelHeader)
		m.DCUInfo = dcuInfo.(*ModelDCUInfo)
		m.SysLoad = sysLoad.(*ModelSysLoad)
		m.ProcessInfo = pidinfo.(*ModelProcessInfo)
		return m, nil
	}
	return m, nil
}

func (m *ModelMain) View() string {
	return m.Header.View() + m.DCUInfo.View() + m.SysLoad.View() + m.ProcessInfo.View() + "\n"
}

var myBorder = lipgloss.Border{
	Top:          "═",
	TopLeft:      "╒",
	TopRight:     "╕",
	Bottom:       "═",
	BottomLeft:   "╘",
	BottomRight:  "╛",
	Left:         "│",
	Right:        "│",
	MiddleLeft:   "├",
	MiddleRight:  "┤",
	Middle:       "┼",
	MiddleTop:    "┬",
	MiddleBottom: "┴",
}

func initModelInfo(model *ModelMsg) error {
	model.MyVersion = DCUTopVersion
	model.index = 0
	model.t = time.Now()
	ver, err := gpu.GetHYVersionInfo()
	if err != nil {
		return err
	}
	model.Version = ver
	if model.index%20 == 0 {
		backend.UpdateDCUInfo(true)
	} else {
		backend.UpdateDCUInfo(false)
	}
	model.DCUInfo = backend.GetDCUInfo()
	model.systemInfo, err = utils.GetSysInfo()
	model.DCUPidInfo = backend.GetDCUProcessInfo()
	return err
}

// updateModelInfo 更新模型信息
func updateModelInfo(modelMsg *ModelMsg, index uint64, t time.Time) {
	modelMsg.index = index
	modelMsg.t = t
	if modelMsg.index%60 == 0 {
		backend.UpdateDCUInfo(true)
	} else {
		backend.UpdateDCUInfo(false)
	}
	modelMsg.DCUInfo = backend.GetDCUInfo()
	modelMsg.systemInfo, _ = utils.GetSysInfo()
	modelMsg.DCUPidInfo = backend.GetDCUProcessInfo()
}
