package main

import (
	"bytes"
	"embed"
	"fmt"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"syscall"
	"text/template"
)

//go:embed bin/*
var embeddedFrpc embed.FS

// 获取当前平台对应的 frpc 路径（从 embed 解压到临时目录）
func getFrpcPath() (string, error) {
	var fileName string

	switch {
	case runtime.GOOS == "windows" && runtime.GOARCH == "amd64":
		fileName = "frpc_windows_amd64.exe"
	case runtime.GOOS == "linux" && runtime.GOARCH == "amd64":
		fileName = "frpc_linux_amd64"
	case runtime.GOOS == "linux" && runtime.GOARCH == "arm64":
		fileName = "frpc_linux_arm64"
	default:
		// 降级：尝试从 PATH 中查找 frpc
		path, err := exec.LookPath("frpc")
		if err == nil {
			return path, nil
		}
		return "", fmt.Errorf("不支持的平台: %s/%s，且 PATH 中未找到 frpc", runtime.GOOS, runtime.GOARCH)
	}

	// 从 embed 读取对应文件
	data, err := embeddedFrpc.ReadFile("bin/" + fileName)
	if err != nil {
		// 如果 embed 中没有，降级到 PATH
		path, lookErr := exec.LookPath("frpc")
		if lookErr == nil {
			return path, nil
		}
		return "", fmt.Errorf("未找到 frpc 文件 (embed 和 PATH 均无): %w", err)
	}

	// 写入临时目录
	tmpPath := os.TempDir() + "/frpc"
	if runtime.GOOS == "windows" {
		tmpPath += ".exe"
	}
	if err := os.WriteFile(tmpPath, data, 0755); err != nil {
		return "", fmt.Errorf("写入临时文件失败: %w", err)
	}
	return tmpPath, nil
}

// frpc.toml 模板 - 完全复制你的配置文件结构
const frpcTemplate = `serverAddr = "{{.ServerAddr}}"
serverPort = {{.ServerPort}}

[auth]
token = "{{.Token}}"

[log]
to = "./frpc.log"
level = "{{.LogLevel}}"
maxDays = {{.LogMaxDays}}

[transport]
tcpMux = {{.TcpMux}}
tcpMuxKeepaliveInterval = {{.TcpMuxKeepalive}}
heartbeatInterval = {{.HeartbeatInterval}}
heartbeatTimeout = {{.HeartbeatTimeout}}
poolCount = {{.PoolCount}}

{{range .Proxies}}
[[proxies]]
name = "{{.Name}}"
type = "{{.Type}}"
localIP = "{{.LocalIP}}"
localPort = {{.LocalPort}}
remotePort = {{.RemotePort}}
{{end}}`

// GenerateFrpcConfig 生成 frpc.toml 配置文件
func GenerateFrpcConfig() error {
	cfg, err := GetGlobalConfig()
	if err != nil {
		return fmt.Errorf("读取全局配置失败: %w", err)
	}

	proxies, err := GetProxies()
	if err != nil {
		return fmt.Errorf("读取隧道列表失败: %w", err)
	}

	var activeProxies []Proxy
	for _, p := range proxies {
		if p.Enabled {
			activeProxies = append(activeProxies, p)
		}
	}

	data := struct {
		*GlobalConfig
		Proxies []Proxy
	}{
		GlobalConfig: cfg,
		Proxies:      activeProxies,
	}

	tmpl, err := template.New("frpc").Parse(frpcTemplate)
	if err != nil {
		return fmt.Errorf("解析模板失败: %w", err)
	}

	var buf bytes.Buffer
	err = tmpl.Execute(&buf, data)
	if err != nil {
		return fmt.Errorf("渲染模板失败: %w", err)
	}

	err = os.WriteFile("./frpc.toml", buf.Bytes(), 0644)
	if err != nil {
		return fmt.Errorf("写入配置文件失败: %w", err)
	}

	return nil
}

// StartFrpc 启动 frpc（后台运行）
func StartFrpc() error {
	frpcPath, err := getFrpcPath()
	if err != nil {
		return fmt.Errorf("获取 frpc 路径失败: %w", err)
	}

	// 检查配置文件是否存在
	if _, err := os.Stat("./frpc.toml"); os.IsNotExist(err) {
		if err := GenerateFrpcConfig(); err != nil {
			return fmt.Errorf("生成配置文件失败: %w", err)
		}
	}

	// 先检查是否已在运行
	running, _ := GetFrpcStatus()
	if running {
		return nil // 已经在运行，不重复启动
	}

	cmd := exec.Command(frpcPath, "-c", "./frpc.toml")
	// Windows 下需要隐藏窗口（可选）
	if runtime.GOOS == "windows" {
		cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
	}
	err = cmd.Start()
	if err != nil {
		return fmt.Errorf("启动 frpc 失败: %w", err)
	}
	return nil
}

// ReloadFrpc 热加载 frpc 配置
func ReloadFrpc() error {
	frpcPath, err := getFrpcPath()
	if err != nil {
		return fmt.Errorf("获取 frpc 路径失败: %w", err)
	}

	// 检查 frpc 是否在运行
	running, err := GetFrpcStatus()
	if err != nil {
		return fmt.Errorf("检查 frpc 状态失败: %w", err)
	}
	if !running {
		// 没运行就直接启动
		return StartFrpc()
	}

	// 执行 reload
	cmd := exec.Command(frpcPath, "reload", "-c", "./frpc.toml")
	output, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("reload 失败: %s, %w", string(output), err)
	}
	return nil
}

// StopFrpc 停止 frpc
func StopFrpc() error {
	if runtime.GOOS == "windows" {
		// Windows 用 taskkill
		cmd := exec.Command("taskkill", "/F", "/IM", "frpc.exe")
		err := cmd.Run()
		if err != nil && !strings.Contains(err.Error(), "not found") {
			return fmt.Errorf("停止 frpc 失败: %w", err)
		}
		return nil
	} else {
		// Linux/Unix 用 pkill
		cmd := exec.Command("pkill", "-f", "frpc")
		err := cmd.Run()
		if err != nil && !strings.Contains(err.Error(), "no process") {
			return fmt.Errorf("停止 frpc 失败: %w", err)
		}
		return nil
	}
}

// GetFrpcStatus 检查 frpc 是否在运行
func GetFrpcStatus() (bool, error) {
	if runtime.GOOS == "windows" {
		// Windows 用 tasklist 检查
		cmd := exec.Command("tasklist", "/FI", "IMAGENAME eq frpc.exe")
		output, err := cmd.CombinedOutput()
		if err != nil {
			return false, nil
		}
		return strings.Contains(string(output), "frpc.exe"), nil
	} else {
		// Linux/Unix 用 pgrep
		cmd := exec.Command("pgrep", "-f", "frpc")
		output, err := cmd.Output()
		if err != nil {
			return false, nil
		}
		return len(output) > 0, nil
	}
}
