package tui

import (
	"fmt"
	"get-container/cmd/hytop/backend"
	"slices"
	"strings"

	"github.com/acarl005/stripansi"
	tea "github.com/charmbracelet/bubbletea"
	"github.com/charmbracelet/lipgloss"
	"github.com/charmbracelet/x/ansi"
	"github.com/shirou/gopsutil/v3/process"
)

type ModelProcessEnv struct {
	w, h             int              // 屏幕宽、高
	pid              int              // 显示的进程pid
	modelMsg         *ModelMsg        // 模型信息
	lineNum          int              // 光标所在的行
	xOffset, yOffset int              // 偏移量
	title            string           // 界面标题
	line             string           // 分割线
	proc             *process.Process // 进程信息
	envs             []string
	styleW, styleH   lipgloss.Style
	envW, envH       int // 环境变量字符串的宽高
	envStr           string
}

func NewModelProcessEnv(w, h, pid int, modelMsg *ModelMsg) *ModelProcessEnv {
	var dev string
	if modelMsg == nil || modelMsg.DCUPidInfo == nil {
		dev = "CPU"
	} else {
		dev = "CPU"
		for _, v := range modelMsg.DCUPidInfo {
			for _, vv := range v {
				if vv.Info.Pid == int32(pid) {
					dev = "DCU"
					break
				}
			}
			if dev == "DCU" {
				break
			}
		}
	}
	style := lipgloss.NewStyle().Foreground(lipgloss.Color("#00fffb7a"))
	header := style.SetString(fmt.Sprintf("Environment of process %d (%s@%s: Compute): ", pid, backend.User, dev)).String()
	proc, err := process.NewProcess(int32(pid))
	style = style.UnsetForeground().Foreground(lipgloss.Color("#6cff4eff"))

	result := &ModelProcessEnv{
		w:        w,
		h:        h,
		pid:      pid,
		lineNum:  -1,
		line:     style.Render(strings.Repeat("#", w)),
		title:    header,
		modelMsg: modelMsg,
		proc:     nil,
		envs:     nil,
		styleW:   lipgloss.NewStyle().MaxWidth(w),
		styleH:   lipgloss.NewStyle().MaxHeight(h),
	}

	if err != nil {
		return result
	}
	cmd, err := proc.Cmdline()
	if err != nil {
		return result
	}
	result.title += cmd
	envs, err := proc.Environ()
	if err != nil {
		return result
	}
	slices.Sort(envs)
	result.envs = envs
	result.addEnvStyle()
	s := strings.Join(result.envs, "\n")
	result.envStr = lipgloss.NewStyle().Width(lipgloss.Width(s)).Render(s)
	result.envW, result.envH = lipgloss.Size(result.envStr)
	return result
}


func (pe *ModelProcessEnv) Init() tea.Cmd {
	return nil
}

// Update 处理光标移动
func (pe *ModelProcessEnv) Update(imsg tea.Msg) (tea.Model, tea.Cmd) {
	// 判断是否需要滚动
	consider := false
	if pe.envH > (pe.h - 2) {
		consider = true
	}
	cW := false
	if pe.envW > pe.w {
		cW = true
	}
	switch msg := imsg.(type) {
	case tea.KeyType:
		switch msg.String() {
		case tea.KeyUp.String():
			if pe.envH == 0 {
				return pe, nil
			}
			if pe.lineNum == -1 {
				if consider {
					pe.lineNum = pe.h - 2
					pe.yOffset = pe.envH - pe.lineNum
				} else {
					pe.lineNum = pe.envH
				}
				return pe, nil
			}
			if consider {
				if pe.lineNum > 1 {
					pe.lineNum--
				} else {
					if pe.yOffset > 0 {
						pe.yOffset--
					}
				}
				return pe, nil
			} else {
				if pe.lineNum > 1 {
					pe.lineNum--
				}
				return pe, nil
			}
		case tea.KeyDown.String():
			if pe.envH == 0 {
				return pe, nil
			}
			if pe.lineNum == -1 {
				pe.lineNum = 1
				return pe, nil
			}
			if consider {
				if pe.lineNum < (pe.h - 2) {
					pe.lineNum++
					return pe, nil
				} else {
					if pe.yOffset+pe.lineNum < pe.envH {
						pe.yOffset++
					}
					return pe, nil
				}
			} else {
				if pe.lineNum < pe.envH {
					pe.lineNum++
					return pe, nil
				}
			}
		case tea.KeyLeft.String():
			if !cW {
				return pe, nil
			}
			if pe.xOffset > 0 {
				pe.xOffset--
				return pe, nil
			}
		case tea.KeyRight.String():
			if !cW {
				return pe, nil
			}
			if pe.xOffset+pe.w < pe.envW {
				pe.xOffset++
				return pe, nil
			}
		}
	}
	return pe, nil
}

func (pe *ModelProcessEnv) View() string {
	sb := strings.Builder{}
	sb.WriteString(pe.title)
	sb.WriteByte('\n')
	sb.WriteString(pe.line)
	sb.WriteByte('\n')
	lines := strings.Split(pe.envStr, "\n")
	l := len(lines[pe.yOffset:])
	for k, line := range lines[pe.yOffset:] {
		if k+1 == pe.lineNum {
			sb.WriteString(pe.styleW.Render(ansi.TruncateLeft(HeightLightStyle.Render(stripansi.Strip(line)), pe.xOffset, "")))
		} else {
			sb.WriteString(pe.styleW.Render(ansi.TruncateLeft(line, pe.xOffset, "")))
		}
		if k+1 < l {
			sb.WriteByte('\n')
		}
	}
	return pe.styleH.Render(sb.String())
}

func (pe *ModelProcessEnv) addEnvStyle() {
	if len(pe.envs) == 0 {
		return
	}
	keyStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#8a8af7ff"))
	equalStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#f237ffff"))
	eq := equalStyle.Render("=")
	target := make([]string, 0, len(pe.envs))
	for _, v := range pe.envs {
		if v == "" {
			continue
		}
		fields := strings.SplitN(v, "=", 2)
		if len(fields) != 2 {
			continue
		}
		target = append(target, keyStyle.Render(fields[0])+eq+fields[1])
	}
	pe.envs = nil
	pe.envs = target
}
