package tui

import (
	"encoding/json"
	"fmt"
	"github.com/charmbracelet/bubbles/table"
	"github.com/eiannone/keyboard"
	"github.com/spf13/cast"
	"strings"
	"wireguard-ui/http/vo"
	"wireguard-ui/model"
	"wireguard-ui/service"
	"wireguard-ui/utils"
)

type SettingComponent struct {
	LoginUser *vo.User
	Menu      []string
	Other     *OtherSettingComponent
}

func NewSettingComponent(loginUser *vo.User) *SettingComponent {
	return &SettingComponent{
		LoginUser: loginUser,
		Menu:      []string{"[1] 服务端配置", "[2] 全局设置", "[3] 其他配置", "[q] 返回上一级菜单"},
		Other:     NewOtherSettingComponent(),
	}
}

// Menus
// @description: 设置菜单
// @receiver s
func (s *SettingComponent) Menus() {
	fmt.Println("")
	for _, r := range s.Menu {
		fmt.Println(" -> " + r)
	}

	chooseMenu := readInput("\n请选择: ")
	switch chooseMenu {
	case "1":
		s.ServerSetting()
	case "2":
		s.GlobalSetting()
	case "3":
		s.Other.Menus(s)
	case "q":
		return
	}

}

// ServerSetting
// @description: 服务端配置
// @receiver s
func (s *SettingComponent) ServerSetting() {
	fmt.Println("\n服务端配置")
	// 先读取一下服务端配置
	servConf, err := service.Setting().GetByCode("WG_SERVER")
	if err != nil {
		fmt.Println("获取服务端配置失败: ", err)
		return
	}

	type serverConf struct {
		IpScope        []string `json:"ipScope"`
		ListenPort     int      `json:"listenPort"`
		PrivateKey     string   `json:"privateKey"`
		PublicKey      string   `json:"publicKey"`
		PostUpScript   string   `json:"postUpScript"`
		PostDownScript string   `json:"postDownScript"`
	}

	// 解析出来好渲染
	var conf serverConf
	if err = json.Unmarshal([]byte(servConf.Data), &conf); err != nil {
		fmt.Println("解析服务端配置失败: ", err)
		return
	}

	ipScopeIn := readInput(fmt.Sprintf("请输入IP段多个采用 ',[英文逗号]' 分割，不填写默认当前值，下同，当前值[%s] ：", strings.Replace(strings.Join(conf.IpScope, ","), " ", "", -1)))
	listenPortIn := readInput(fmt.Sprintf("请输入监听端口，当前值[%d]： ", conf.ListenPort))
	privateKeyIn := readInput(fmt.Sprintf("请输入私钥，当前值[%s]： ", conf.PrivateKey))
	publicKeyIn := readInput(fmt.Sprintf("请输入公钥，当前值[%s]： ", conf.PublicKey))
	postUpScriptIn := readInput(fmt.Sprintf("请输入PostUp脚本，当前值[%s]： ", conf.PostUpScript))
	postDownScriptIn := readInput(fmt.Sprintf("请输入PostDown脚本，当前值[%s]： ", conf.PostDownScript))

	if ipScopeIn != "" {
		conf.IpScope = strings.Split(ipScopeIn, ",")
	}
	if listenPortIn != "" {
		conf.ListenPort = cast.ToInt(listenPortIn)
	}
	if privateKeyIn != "" {
		conf.PrivateKey = privateKeyIn
	}
	if publicKeyIn != "" {
		conf.PublicKey = publicKeyIn
	}
	if postUpScriptIn != "" {
		conf.PostUpScript = postUpScriptIn
	}
	if postDownScriptIn != "" {
		conf.PostDownScript = postDownScriptIn
	}

	data, _ := json.Marshal(conf)

	if err := service.Setting().SetData(&model.Setting{
		Code: "WG_SERVER",
		Data: string(data),
	}); err != nil {
		fmt.Println("保存服务端配置失败: ", err)
		return
	}

	fmt.Println("修改服务端配置成功")
	return
}

// GlobalSetting
// @description: 全局设置
// @receiver s
func (s *SettingComponent) GlobalSetting() {
	fmt.Println("\n服务端配置")
	// 先读取一下服务端配置
	globalConf, err := service.Setting().GetByCode("WG_SETTING")
	if err != nil {
		fmt.Println("获取服务端配置失败: ", err)
		return
	}

	type gConf struct {
		MTU                 int      `json:"MTU"`
		ConfigFilePath      string   `json:"configFilePath"`
		DnsServer           []string `json:"dnsServer"`
		EndpointAddress     string   `json:"endpointAddress"`
		FirewallMark        string   `json:"firewallMark"`
		PersistentKeepalive int      `json:"persistentKeepalive"`
		Table               string   `json:"table"`
	}

	// 解析出来好渲染
	var conf gConf
	if err = json.Unmarshal([]byte(globalConf.Data), &conf); err != nil {
		fmt.Println("解析全局配置失败: ", err)
		return
	}

	mtu := readInput(fmt.Sprintf("请输入mtu，不填写默认当前值，下同，当前值[%d] ：", conf.MTU))
	configFilePath := readInput(fmt.Sprintf("请输入配置文件地址，当前值[%s]： ", conf.ConfigFilePath))
	dnsServer := readInput(fmt.Sprintf("请输入dns，多个采用 ',[英文逗号]' 分割，当前值[%s]： ", strings.Replace(strings.Join(conf.DnsServer, ","), " ", "", -1)))
	endpointAddress := readInput(fmt.Sprintf("请输入公网IP，默认系统自动获取，当前值[%s]： ", conf.EndpointAddress))
	firewallMark := readInput(fmt.Sprintf("请输入FirewallMark，当前值[%s]： ", conf.FirewallMark))
	persistentKeepalive := readInput(fmt.Sprintf("请输入PersistentKeepalive，当前值[%d]： ", conf.PersistentKeepalive))
	tableRule := readInput(fmt.Sprintf("请输入Table，当前值[%s]： ", conf.Table))

	if mtu != "" {
		conf.MTU = cast.ToInt(mtu)
	}
	if configFilePath != "" {
		conf.ConfigFilePath = configFilePath
	}
	if dnsServer != "" {
		conf.DnsServer = strings.Split(dnsServer, ",")
	}
	if endpointAddress != "" {
		conf.EndpointAddress = endpointAddress
	} else {
		conf.EndpointAddress = utils.Network().GetHostPublicIP()
	}
	if firewallMark != "" {
		conf.FirewallMark = firewallMark
	}
	if persistentKeepalive != "" {
		conf.PersistentKeepalive = cast.ToInt(persistentKeepalive)
	}
	if tableRule != "" {
		conf.Table = tableRule
	}

	data, _ := json.Marshal(conf)

	if err := service.Setting().SetData(&model.Setting{
		Code: "WG_SETTING",
		Data: string(data),
	}); err != nil {
		fmt.Println("保存全局配置失败: ", err)
		return
	}

	fmt.Println("修改全局配置成功")
	return
}

// OtherSettingComponent
// @description: 其他配置杂项
type OtherSettingComponent struct {
	Setting *SettingComponent
	Menu    []string
}

func NewOtherSettingComponent() *OtherSettingComponent {
	return &OtherSettingComponent{
		Menu: []string{"[1] 列表", "[2] 添加", "[3] 编辑", "[4] 删除", "[q] 返回上一级菜单"},
	}
}

func (s *OtherSettingComponent) Menus(setting *SettingComponent) {
	if s.Setting == nil {
		s.Setting = setting
	}
	fmt.Println("")
	for _, r := range s.Menu {
		fmt.Println(" -> " + r)
	}

	chooseMenu := readInput("\n请选择: ")
	switch chooseMenu {
	case "1":
		s.List(true)
	case "2":
		s.Add()
	case "3":
		s.Edit()
	case "4":
		s.Delete()

	case "q":
		s.Setting.Menus()
	}

}

// List
// @description: 其他配置
// @receiver s
// @param showMenu
func (s *OtherSettingComponent) List(showMenu bool) {
	fmt.Println("\n其他配置列表")
	// 不查询的配置
	var blackList = []string{"WG_SETTING", "WG_SERVER"}

	data, err := service.Setting().GetAllSetting(blackList)
	if err != nil {
		fmt.Println("获取配置失败")
		return
	}

	title := []table.Column{
		{
			Title: "序号",
			Width: 10,
		},
		{
			Title: "编码",
			Width: 40,
		},
		{
			Title: "描述",
			Width: 50,
		},
		{
			Title: "创建时间",
			Width: 30,
		},
		{
			Title: "更新时间",
			Width: 30,
		},
	}

	var result [][]string
	for i, v := range data {
		result = append(result, []string{
			cast.ToString(i + 1),
			v.Code,
			v.Describe,
			v.CreatedAt.Format("2006-01-02 15:04:05"),
			v.UpdatedAt.Format("2006-01-02 15:04:05"),
		})
	}

	Show(GenerateTable(title, result))
	if showMenu {
		s.Menus(nil)
	}
}

// Add
// @description: 新增其他配置
// @receiver s
func (s *OtherSettingComponent) Add() {
	fmt.Println("\n新增其他配置")

	code := readInput("请输入配置编码，此编码是唯一编码不可重复：")
	desc := readInput("请输入配置描述：")

	// 监听键盘事件，只监听 + 和 - 和 enter
	if err := keyboard.Open(); err != nil {
		return
	}

	defer func() {
		_ = keyboard.Close()
	}()

	// + <=> 43 | - <=> 45 | enter <=> 0
	fmt.Println("请按下 + 或者 - 进行配置项的新增和删除")
	fmt.Println("每一项配置如此： key=val ")
	fmt.Println("确认输入完成后 enter[按一次代表当前配置项输入完成，两次代表新增完成]")
	fmt.Println("首先进入时请输入 + 进行第一个配置项填写")
	var breakCycle bool
	var keyVal []string
	for {
		char, _, err := keyboard.GetKey()
		if err != nil {
			break
		}

		if breakCycle {
			break
		}

		switch char {
		case 0:
			// 收到enter事件触发，执行后面的
			var dm = make(map[string]any)
			for _, kv := range keyVal {
				kvs := strings.Split(kv, "=")
				key := kvs[0]
				val := kvs[1]
				dm[key] = val
			}

			dms, err := json.Marshal(dm)
			if err != nil {
				breakCycle = true
				continue
			}

			if err = service.Setting().SetData(&model.Setting{
				Code:     code,
				Data:     string(dms),
				Describe: desc,
			}); err != nil {
				breakCycle = true
				fmt.Println("保存配置失败: ", err.Error())
				continue
			}

			fmt.Println("保存配置成功")
			s.List(true)

			breakCycle = true
		case 43:
			keyVal = append(keyVal, readInput("请输入配置项："))
		case 45:
			keyVal = keyVal[:len(keyVal)-1]
			fmt.Println("已删除最后一个配置项，当前配置项为：", keyVal)
		}

	}

}

// Edit
// @description: 编辑
// @receiver s
func (s *OtherSettingComponent) Edit() {
	fmt.Println("\n编辑其他配置")

	s.List(false)

	code := readInput("请输入需要编辑的配置编码：")

	// 通过编码查询配置
	setting, err := service.Setting().GetByCode(code)
	if err != nil {
		fmt.Println("查找["+code+"]配置失败：", err.Error())
		return
	}

	desc := readInput("请输入需要编辑的配置描述：")
	if desc != "" {
		setting.Describe = desc
	}

	var kvm = make(map[string]any)
	if err = json.Unmarshal([]byte(setting.Data), &kvm); err != nil {
		fmt.Println("配置解析失败: ", err.Error())
		return
	}

	for k, v := range kvm {
		valIn := readInput(fmt.Sprintf("请输入配置项值，仅能修改值，当前键值对：%s=%v ：", k, v))
		if valIn != "" {
			kvm[k] = valIn
		}
	}

	// 处理以下数据
	kvmStr, err := json.Marshal(kvm)
	if err != nil {
		fmt.Println("序列化数据失败: ", err.Error())
		return
	}

	setting.Data = string(kvmStr)

	if err = service.Setting().SetData(setting); err != nil {
		fmt.Println("修改配置失败: ", err.Error())
		return
	}

	fmt.Println("修改配置成功")
}

// Delete
// @description: 删除
// @receiver s
func (s *OtherSettingComponent) Delete() {
	fmt.Println("\n 删除指定配置")

	s.List(false)

	code := readInput("请输入要删除的配置项编码：")
	// 查询配置是否存在
	if err := service.Setting().Model(&model.Setting{}).
		Where("code NOT IN (?)", []string{"WG_SETTING", "WG_SERVER"}).
		Where("code = ?", code).Delete(&model.Setting{}).Error; err != nil {
		fmt.Println("删除[" + code + "]配置失败")
		return
	}

	fmt.Println("删除成功")

	s.List(true)

}
