package service

import (
	"encoding/json"
	"fmt"
	slog "gitee.ltd/lxh/logger/log"
	"gorm.io/gorm"
	"strings"
	gdb "wireguard-ui/global/client"
	"wireguard-ui/http/param"
	"wireguard-ui/http/vo"
	"wireguard-ui/model"
	"wireguard-ui/template/render_data"
	"wireguard-ui/utils"
)

type setting struct{ *gorm.DB }

func Setting() setting {
	return setting{gdb.DB}
}

func (s setting) SetData(data *model.Setting) error {
	// 判断code是否已经存在
	var count int64
	if err := s.Model(&model.Setting{}).Where("code = ?", data.Code).Count(&count).Error; err != nil {
		return err
	}

	// 存在就更新，反之新增
	if count > 0 {
		return s.Where("code = ?", data.Code).Updates(&data).Error
	}

	return s.Create(&data).Error
}

// GetWGSetForConfig
// @description: 获取全局配置
// @receiver s
// @return data
// @return err
func (s setting) GetWGSetForConfig() (data *render_data.ServerSetting, err error) {
	var rs *model.Setting
	if err = s.Model(&model.Setting{}).Where("code = ?", "WG_SETTING").Take(&rs).Error; err != nil {
		return
	}

	if err = json.Unmarshal([]byte(rs.Data), &data); err != nil {
		return
	}

	return
}

// GetWGServerForConfig
// @description: 获取wireguard服务端配置为了渲染数据
// @receiver s
// @return render_data
// @return err
func (s setting) GetWGServerForConfig() (data *render_data.Server, err error) {
	var rs *model.Setting
	if err = s.Model(&model.Setting{}).Where("code = ?", "WG_SERVER").Take(&rs).Error; err != nil {
		return
	}

	if err = json.Unmarshal([]byte(rs.Data), &data); err != nil {
		return
	}

	// 获取一下全局的服务配置
	gs, err := s.GetWGSetForConfig()
	if err != nil {
		return
	}

	data.MTU = gs.MTU
	data.Table = gs.Table
	return
}

// GetAllSetting
// @description: 获取全部配置
// @receiver s
// @param blackList
// @return data
// @return err
func (s setting) GetAllSetting(blackList []string) (data []vo.SettingItem, err error) {
	err = s.Model(&model.Setting{}).Select("code, data, describe,created_at,updated_at").Where("code not in ?", blackList).Find(&data).Error
	return
}

// GetByCode
// @description: 获取指定code的配置
// @receiver s
// @param code
// @return data
// @return err
func (s setting) GetByCode(code string) (data *model.Setting, err error) {
	err = s.Model(&model.Setting{}).Where("code = ?", code).Take(&data).Error
	return
}

// Export
// @description: 导出
// @receiver s
// @return data
// @return err
func (s setting) Export() (data vo.Export, err error) {
	// 先查询global配置
	var gs, ss *model.Setting
	if err = s.Model(&model.Setting{}).Where("code = ?", "WG_SETTING").Take(&gs).Error; err != nil {
		return
	}
	if err = json.Unmarshal([]byte(gs.Data), &data.Global); err != nil {
		return
	}

	// 查询server配置
	if err = s.Model(&model.Setting{}).Where("code = ?", "WG_SERVER").Take(&ss).Error; err != nil {
		return
	}
	if err = json.Unmarshal([]byte(ss.Data), &data.Server); err != nil {
		return
	}

	// 查询client配置
	var clients []vo.ClientItem
	if err = s.Model(&model.Client{}).Select("id,name,email,ip_allocation as ip_allocation_str," +
		"allowed_ips as allowed_ips_str,extra_allowed_ips as extra_allowed_ips_str," +
		"endpoint,use_server_dns,keys as keys_str," +
		"enabled,offline_monitoring").Order("created_at DESC").Find(&clients).Error; err != nil {
		return
	}

	for i, v := range clients {
		if v.KeysStr != "" {
			_ = json.Unmarshal([]byte(v.KeysStr), &clients[i].Keys)
		}
		if v.IpAllocationStr != "" {
			clients[i].IpAllocation = strings.Split(v.IpAllocationStr, ",")
		}
		if v.AllowedIpsStr != "" {
			clients[i].AllowedIps = strings.Split(v.AllowedIpsStr, ",")
		} else {
			clients[i].AllowedIps = []string{}
		}
		if v.ExtraAllowedIpsStr != "" {
			clients[i].ExtraAllowedIps = strings.Split(v.ExtraAllowedIpsStr, ",")
		} else {
			clients[i].ExtraAllowedIps = []string{}
		}
	}

	// 查询其他配置
	var others []vo.Other
	if err = s.Model(&model.Setting{}).Where("code not in ?", []string{"WG_SETTING", "WG_SERVER"}).Find(&others).Error; err != nil {
		return
	}

	data.Other = others
	cj, _ := json.Marshal(clients)
	_ = json.Unmarshal(cj, &data.Clients)

	return
}

// Import
// @description: 导入
// @receiver s
// @param data
// @return err
func (s setting) Import(data *vo.Export, loginUser *vo.User) (err error) {
	// 获取导入系统的公网IP地址
	pubAddr := utils.Network().GetHostPublicIP()
	data.Global.EndpointAddress = pubAddr
	// 先更新global配置
	gst, _ := json.Marshal(data.Global)
	gs := &model.Setting{
		Code:     "WG_SETTING",
		Data:     string(gst),
		Describe: "服务端全局配置",
	}
	if err = s.SetData(gs); err != nil {
		return
	}

	st, _ := json.Marshal(data.Server)
	ss := &model.Setting{
		Code:     "WG_SERVER",
		Data:     string(st),
		Describe: "服务端配置",
	}
	if err = s.SetData(ss); err != nil {
		return
	}

	// 更新client配置
	for _, v := range data.Clients {
		keys := &param.Keys{
			PrivateKey:   v.Keys.PrivateKey,
			PublicKey:    v.Keys.PublicKey,
			PresharedKey: v.Keys.PresharedKey,
		}
		cc := param.SaveClient{
			Name:              v.Name,
			Email:             v.Email,
			IpAllocation:      v.IpAllocation,
			AllowedIps:        v.AllowedIps,
			ExtraAllowedIps:   v.ExtraAllowedIps,
			UseServerDns:      v.UseServerDns,
			Keys:              keys,
			Enabled:           v.Enabled,
			OfflineMonitoring: v.OfflineMonitoring,
		}

		if v.Endpoint != "" {
			port := strings.Split(v.Endpoint, ":")[1]
			endpoint := fmt.Sprintf("%s:%s", pubAddr, port)
			cc.Endpoint = endpoint
		}

		if err := Client().SaveClient(cc, loginUser); err != nil {
			slog.Errorf("客户端[%s]导入失败: %v", v.Name, err)
			continue
		}
	}

	// 其他配置写入
	for _, v := range data.Other {
		if err = s.SetData(&model.Setting{
			Code:     v.Code,
			Data:     v.Data,
			Describe: v.Describe,
		}); err != nil {
			slog.Errorf("其他配置[%s]导入失败: %v", v.Code, err)
			continue
		}
	}

	return nil
}
