package api

import (
	"encoding/json"
	"fmt"
	"gitee.ltd/lxh/logger/log"
	"github.com/gin-gonic/gin"
	"os"
	"strings"
	"wireguard-dashboard/http/param"
	"wireguard-dashboard/model/entity"
	"wireguard-dashboard/model/template_data"
	"wireguard-dashboard/queues"
	"wireguard-dashboard/repository"
	"wireguard-dashboard/utils"
)

type clients struct{}

func Client() clients {
	return clients{}
}

// List
// @description: 客户端列表
// @receiver clients
// @param c
func (clients) List(c *gin.Context) {
	var p param.ClientList
	if err := c.ShouldBind(&p); err != nil {
		utils.GinResponse(c).FailedWithErr("参数错误", err)
		return
	}

	data, total, err := repository.Client().List(p)
	if err != nil {
		utils.GinResponse(c).FailedWithMsg("获取失败")
		return
	}

	utils.GinResponse(c).OkWithPage(data, total, p.Current, p.Size)
}

// Save
// @description: 新增/更新客户端
// @receiver clients
// @param c
func (clients) Save(c *gin.Context) {
	var p param.SaveClient
	if err := c.ShouldBind(&p); err != nil {
		utils.GinResponse(c).FailedWithErr("参数错误", err)
		return
	}

	info, ok := c.Get("user")
	if !ok {
		utils.GinResponse(c).FailedWithMsg("获取信息失败")
		return
	}

	_, err := repository.Client().Save(p, info.(*entity.User).Id)
	if err != nil {
		utils.GinResponse(c).FailedWithErr("操作失败", err)
		return
	}

	go func() {
		if err = queues.PutAsyncWireguardConfigFile(p.ServerId); err != nil {
			log.Errorf("[新增/编辑客户端]同步配置文件失败: %v", err.Error())
		}
	}()

	utils.GinResponse(c).OK()
}

// Delete
// @description: 删除客户端
// @receiver clients
// @param c
func (clients) Delete(c *gin.Context) {
	var id = c.Param("id")
	if id == "" || id == "undefined" {
		utils.GinResponse(c).FailedWithMsg("参数错误")
		return
	}

	if err := repository.Client().Delete(id); err != nil {
		utils.GinResponse(c).FailedWithMsg("操作失败")
		return
	}

	utils.GinResponse(c).OK()
}

// Download
// @description: 下载配置文件
// @receiver clients
// @param c
func (clients) Download(c *gin.Context) {
	var id = c.Param("id")
	if id == "" || id == "undefined" {
		utils.GinResponse(c).FailedWithMsg("参数错误")
		return
	}

	data, err := repository.Client().GetById(id)
	if err != nil {
		utils.GinResponse(c).FailedWithMsg("获取失败")
		return
	}

	var keys template_data.Keys
	_ = json.Unmarshal([]byte(data.Keys), &keys)

	setting, err := repository.System().GetServerSetting()
	if err != nil {
		utils.GinResponse(c).FailedWithMsg("获取设置失败")
		return
	}

	// 处理一下数据
	execData := template_data.ClientConfig{
		PrivateKey:          keys.PrivateKey,
		IpAllocation:        data.IpAllocation,
		MTU:                 setting.MTU,
		DNS:                 strings.Join(setting.DnsServer, ","),
		PublicKey:           keys.PublicKey,
		PresharedKey:        keys.PresharedKey,
		AllowedIPS:          data.AllowedIps,
		Endpoint:            setting.EndpointAddress,
		ListenPort:          data.Server.ListenPort,
		PersistentKeepalive: setting.PersistentKeepalive,
	}

	// 不同环境下处理文件路径
	var outPath = "/tmp/" + fmt.Sprintf("%s.conf", data.Name)
	var templatePath = "./template/wg.client.conf"
	if os.Getenv("GIN_MODE") != "release" {
		outPath = "E:\\Workspace\\Go\\wireguard-dashboard\\template\\" + fmt.Sprintf("%s.conf", data.Name)
		templatePath = "E:\\Workspace\\Go\\wireguard-dashboard\\template\\wg.client.conf"
	}

	// 渲染数据
	parseTemplate, err := utils.Template().Parse(templatePath)
	if err != nil {
		utils.GinResponse(c).FailedWithMsg("读取模板文件失败")
		return
	}

	err = utils.Template().Execute(parseTemplate, execData, outPath)
	if err != nil {
		utils.GinResponse(c).FailedWithMsg("文件渲染失败")
		return
	}

	// 输出文件流
	c.Header("Content-Type", "application/octet-stream")
	c.Header("Content-Disposition", "attachment; filename="+outPath)
	c.Header("Content-Transfer-Encoding", "binary")
	c.Header("Connection", "keep-alive")
	c.File(outPath)
	if err = os.Remove(outPath); err != nil {
		log.Errorf("删除临时文件失败: %s", err.Error())
	}
}

// GenerateQrCode
// @description: 生成客户端信息二维码
// @receiver clients
// @param c
func (clients) GenerateQrCode(c *gin.Context) {
	var id = c.Param("id")
	if id == "" || id == "undefined" {
		utils.GinResponse(c).FailedWithMsg("参数错误")
		return
	}

	data, err := repository.Client().GetById(id)
	if err != nil {
		utils.GinResponse(c).FailedWithMsg("获取失败")
		return
	}

	var keys template_data.Keys
	_ = json.Unmarshal([]byte(data.Keys), &keys)

	setting, err := repository.System().GetServerSetting()
	if err != nil {
		utils.GinResponse(c).FailedWithMsg("获取设置失败")
		return
	}

	// 处理一下数据
	execData := template_data.ClientConfig{
		PrivateKey:          keys.PrivateKey,
		IpAllocation:        data.IpAllocation,
		MTU:                 setting.MTU,
		PublicKey:           keys.PublicKey,
		PresharedKey:        keys.PresharedKey,
		AllowedIPS:          data.AllowedIps,
		Endpoint:            setting.EndpointAddress,
		ListenPort:          data.Server.ListenPort,
		PersistentKeepalive: setting.PersistentKeepalive,
	}

	// 不同环境下处理文件路径
	var outPath = "/tmp/" + fmt.Sprintf("%s.conf", data.Name)
	var templatePath = "./template/wg.client.conf"
	if os.Getenv("GIN_MODE") != "release" {
		outPath = "E:\\Workspace\\Go\\wireguard-dashboard\\template\\" + fmt.Sprintf("%s.conf", data.Name)
		templatePath = "E:\\Workspace\\Go\\wireguard-dashboard\\template\\wg.client.conf"
	}

	// 渲染数据
	parseTemplate, err := utils.Template().Parse(templatePath)
	if err != nil {
		utils.GinResponse(c).FailedWithMsg("读取模板文件失败")
		return
	}

	err = utils.Template().Execute(parseTemplate, execData, outPath)
	if err != nil {
		utils.GinResponse(c).FailedWithMsg("文件渲染失败")
		return
	}

	// 读取文件内容
	fileContent, err := os.ReadFile(outPath)
	if err != nil {
		utils.GinResponse(c).FailedWithMsg("读取文件失败")
		return
	}

	png, err := utils.QRCode().GenerateQrCodeBase64(fileContent, 256)
	if err != nil {
		utils.GinResponse(c).FailedWithErr("生成二维码失败", err)
		return
	}

	if err = os.Remove(outPath); err != nil {
		log.Errorf("删除临时文件失败: %s", err.Error())
	}

	utils.GinResponse(c).OKWithData(map[string]interface{}{
		"qrCode": png,
	})
}