package machine

import (
	"encoding/json"
	"fmt"
	"hash/fnv"
	"os"
	"runtime"
	"time"

	"be.ems/src/framework/cmd"
	"be.ems/src/framework/config"
	"be.ems/src/framework/constants"
	"be.ems/src/framework/logger"
	"be.ems/src/framework/utils/crypto"
	"be.ems/src/framework/utils/parse"
)

// 机器的唯一标识符
var Code string

// 初始信息
var LaunchInfo map[string]any

// codeGenerate 生成机器的唯一标识符
func codeGenerate() string {
	var machineID string

	// 获取主机名
	hostname, err := os.Hostname()
	if err != nil {
		panic(err)
	}
	machineID += hostname

	// 获取 CPU 信息
	numCPU := runtime.NumCPU()
	machineID += fmt.Sprintf("%d", numCPU)

	// 获取操作系统信息
	osInfo := runtime.GOOS
	machineID += osInfo

	// 使用哈希函数生成机器码
	h := fnv.New32a()
	h.Write([]byte(machineID))
	machineCode := h.Sum32()

	return fmt.Sprintf("%x", machineCode)
}

// 网管本地路径
func filePath() string {
	filePath := "/usr/local/etc/omc/machine.ini"
	if runtime.GOOS == "windows" {
		filePath = fmt.Sprintf("C:%s", filePath)
	}
	return filePath
}

// codeFileRead 读取机器保留的信息
func codeFileRead() (map[string]any, error) {
	var mapData map[string]any
	// 读取文件内容
	bytes, err := os.ReadFile(filePath())
	if err != nil {
		logger.Warnf("CodeFileRead ReadFile => %s", err.Error())
		return mapData, fmt.Errorf("not file")
	}
	content := string(bytes)
	// 解密
	hostKey := config.Get("aes.hostKey").(string)
	contentDe, err := crypto.AESDecryptBase64(content, hostKey)
	if err != nil {
		logger.Errorf("CodeFileRead decrypt: %v", err.Error())
		return mapData, fmt.Errorf("decrypt fail")
	}
	// 序列化Map
	mapData, err = parse.ConvertConfigToMap("json", string(contentDe))
	if err != nil {
		logger.Warnf("CodeFileRead ConvertConfigToMap => %s", err.Error())
		return mapData, fmt.Errorf("content error")
	}
	return mapData, nil
}

// codeFileWrite 写入机器保留的信息
func codeFileWrite(data map[string]any) error {
	jsonByte, _ := json.Marshal(data)
	// 加密
	hostKey := config.Get("aes.hostKey").(string)
	contentEn, err := crypto.AESEncryptBase64(string(jsonByte), hostKey)
	if err != nil {
		logger.Errorf("insert encrypt: %v", err.Error())
		return fmt.Errorf("encrypt fail")
	}
	return parse.ConvertConfigToFile("txt", filePath(), contentEn)
}

// Launch 记录首次安装启动初始信息
func Launch() {
	Code = codeGenerate()
	// 检查文件是否存在
	if _, err := os.Stat(filePath()); err != nil {
		LaunchInfo = map[string]any{
			"code":    Code,                   // 机器码
			"useTime": time.Now().UnixMilli(), // 首次使用时间

			constants.LAUNCH_BOOTLOADER:          true, // 启动引导
			constants.LAUNCH_BOOTLOADER + "Time": 0,    // 引导完成时间
		}
		codeFileWrite(LaunchInfo)
	} else {
		// 读取记录文件
		data, err := codeFileRead()
		if err != nil {
			// 文件异常就重新生成
			os.Remove(filePath())
			Launch()
			return
		}
		LaunchInfo = data
	}
}

// SetLaunchInfo 新增额外的初始信息
func SetLaunchInfo(info map[string]any) error {
	if info == nil {
		return fmt.Errorf("not info")
	}

	// 固定值禁止变更
	constKeys := []string{"code", "useTime"}
	for k, v := range info {
		constKey := false
		for _, ck := range constKeys {
			if ck == k {
				constKey = true
				break
			}
		}
		if constKey {
			continue
		} else {
			LaunchInfo[k] = v
		}
	}
	return codeFileWrite(LaunchInfo)
}

// Bootloader 启动引导标记
func Bootloader(flag bool) error {
	return SetLaunchInfo(map[string]any{
		constants.LAUNCH_BOOTLOADER:          flag,                   // 启动引导 true开 false关
		constants.LAUNCH_BOOTLOADER + "Time": time.Now().UnixMilli(), // 引导完成时间
	})
}

// Reset 引导数据重置
func Reset() error {
	// 重置数据库
	if runtime.GOOS == "windows" {
		// return fmt.Errorf("not support window")
	} else {
		// 重置数据库
		if _, err := cmd.Exec("/usr/local/etc/omc/script/setup.sh -i"); err != nil {
			return err
		}
		// 重启服务
		if _, err := cmd.Execf("nohup sh -c \"sleep 1s && %s\" > /dev/null 2>&1 &", "sudo systemctl restart omc"); err != nil {
			return err
		}
	}

	// 重置引导标记
	if err := Bootloader(true); err != nil {
		return err
	}

	return nil
}
