package core

import (
	"errors"
	"fmt"
	"github.com/goWxHook/goWxHook/resource"
	"github.com/goWxHook/goWxHook/utils"
	"github.com/goWxHook/goWxHook/utils/tcp"
	"log/slog"
	"os"
	"os/exec"
	"strconv"
	"time"
)

var (
	GlobalCallUrl string
	lastErrorStr  string
	GlobalDebug   bool
)

func init() {
	files := map[string]*[]byte{
		"Helper_3.9.10.19.dll": &resource.HelperDll,
		"Loader_3.9.10.19.dll": &resource.LoaderDll,
		"callexe.exe":          &resource.CallExe,
		"HPSocket4C.dll":       &resource.HPSocket4C,
	}
	for name, val := range files {
		if !utils.FileExists(name) {
			if err := utils.WriteFile(name, *val); err != nil {
				panic(err)
			}
		}
	}
}

// 获取宿主机上下一个可用的Api端口，检测端口和+1的端口是否可用
func getNextAvailableApiPort(fromPort int) (int, error) {
	const lowerLimit = 1000
	const upperLimit = 65535
	searchDown := (fromPort - lowerLimit) > (upperLimit - fromPort)
	var step int
	if searchDown {
		step = -1
	} else {
		step = 1
	}

	var m = make(map[int]bool)
	for {
		fromPort += step
		if fromPort < lowerLimit || fromPort > upperLimit {
			return 0, errors.New("no available port")
		}
		portUsed := tcp.CheckPortConnection("127.0.0.1", fromPort)
		m[fromPort] = portUsed
		if !portUsed {
			beforePort := fromPort - step
			if v, ok := m[beforePort]; ok && !v {
				if searchDown {
					return fromPort, nil
				} else {
					return beforePort, nil
				}
			}
		}
	}
}

// WxModuleInit 初始化微信模块
// 除此之外，系统主动检测启动端口用于dll和服务内部统信
func WxModuleInit(listenerPort int, debug bool) error {
	GlobalDebug = debug
	if GlobalDebug {
		slog.SetLogLoggerLevel(slog.LevelDebug)
	}
	// 获取内部服务使用端口
	port, err := getNextAvailableApiPort(listenerPort)
	if err != nil {
		return err
	}
	var lserr error
	go func() {
		lserr = registerWxCallBackListen(port + 1)
	}()
	time.Sleep(2 * time.Second)
	if lserr != nil {
		return lserr
	}
	args := []string{strconv.Itoa(os.Getpid()), strconv.Itoa(port)}
	cmd := exec.Command(".\\callexe.exe", args...)
	err = cmd.Start()
	if err != nil {
		return err
	}
	// 等待3秒进程启动
	time.Sleep(3 * time.Second)
	GlobalCallUrl = fmt.Sprintf("http://127.0.0.1:%d", port)
	slog.Info(fmt.Sprintf("启动微信监听 %d\n", port))
	api := WxApi{}
	if err := api.Ping(); err != nil {
		return err
	}
	return nil
}
