/*
持续挖矿
1，在主配置文件中选择是否开启
2，开启后将读取挖矿配置(mining.conf)
3，根据配置，启动相应的挖矿软件开始挖矿
4，接收到tcp协议传送过来的新挖矿任务后，停止当前挖矿，并开启新的挖矿
5，新挖矿任务到期或结束后，重新开启挖矿

配置文件：算法、挖矿软件、挖矿配置(算法、钱包、矿工号、挖矿地址)
*/
package sustain

import (
	message "client/internal/msg"
	"client/internal/src"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"

	"gopkg.in/ini.v1"
)

// SustainMiningConfig 持续挖矿配置
type SustainMiningConfig struct {
	Enabled      bool   // 是否启用持续挖矿
	Algo         string // 算法
	Coin         string // 币种
	Miner        string // 挖矿软件 (lolminer/bzminer/rigel)
	PoolUrl      string // 矿池地址
	Wallet       string // 钱包地址
	WorkerID     string // 矿工号
	PoolUser     string // 矿池账号（可选）
	WalletMining bool   // 是否使用钱包挖矿
}

// SustainMiner 持续挖矿管理器
type SustainMiner struct {
	mu             sync.Mutex
	config         SustainMiningConfig
	miningConfig   message.MiningConfig
	os             *src.SystemServer
	osName         string
	currentProcess *exec.Cmd     // 当前挖矿进程
	isRunning      bool          // 是否正在运行持续挖矿
	isPaused       bool          // 是否被暂停（因为有新任务）
	stopChan       chan struct{} // 停止信号
}

// NewSustainMiner 创建持续挖矿管理器
func NewSustainMiner(os *src.SystemServer, osName string, miningConfig message.MiningConfig) *SustainMiner {
	return &SustainMiner{
		os:           os,
		osName:       osName,
		miningConfig: miningConfig,
		stopChan:     make(chan struct{}),
	}
}

// LoadConfig 从配置文件加载持续挖矿配置
func (s *SustainMiner) LoadConfig() error {
	var confFile string
	if runtime.GOOS == "windows" {
		confFile = "mining.windows.conf"
	} else {
		confFile = "mining.linux.conf"
	}

	cfg, err := ini.Load(confFile)
	if err != nil {
		return fmt.Errorf("读取配置文件失败: %v", err)
	}

	// 读取 [sustain] 部分
	section := cfg.Section("sustain")
	s.config.Enabled, _ = section.Key("enabled").Bool()
	if !s.config.Enabled {
		log.Println("持续挖矿未启用")
		return nil
	}

	// 读取配置值，并去掉可能的引号
	s.config.Algo = strings.Trim(section.Key("algo").String(), `"`)
	s.config.Coin = strings.Trim(section.Key("coin").String(), `"`)
	s.config.Miner = strings.Trim(section.Key("miner").String(), `"`)
	s.config.PoolUrl = strings.Trim(section.Key("pool_url").String(), `"`)
	s.config.Wallet = strings.Trim(section.Key("wallet").String(), `"`)
	s.config.WorkerID = strings.Trim(section.Key("worker_id").String(), `"`)
	s.config.PoolUser = strings.Trim(section.Key("pool_user").String(), `"`)
	s.config.WalletMining, _ = section.Key("wallet_mining").Bool()

	// 验证配置
	if s.config.Algo == "" || s.config.Coin == "" || s.config.Miner == "" ||
		s.config.PoolUrl == "" || s.config.Wallet == "" || s.config.WorkerID == "" {
		return fmt.Errorf("持续挖矿配置不完整")
	}

	// 验证挖矿软件路径
	switch strings.ToLower(s.config.Miner) {
	case "lolminer":
		if s.miningConfig.LolMinerPath == "" {
			return fmt.Errorf("lolminer 路径未配置")
		}
	case "bzminer":
		if s.miningConfig.BzMinerPath == "" {
			return fmt.Errorf("bzminer 路径未配置")
		}
	case "rigel":
		if s.miningConfig.RigelPath == "" {
			return fmt.Errorf("rigel 路径未配置")
		}
	default:
		return fmt.Errorf("不支持的挖矿软件: %s", s.config.Miner)
	}

	log.Printf("持续挖矿配置加载成功: 算法=%s, 币种=%s, 挖矿软件=%s", s.config.Algo, s.config.Coin, s.config.Miner)
	return nil
}

// Start 启动持续挖矿
func (s *SustainMiner) Start() error {
	s.mu.Lock()
	defer s.mu.Unlock()

	if !s.config.Enabled {
		return nil
	}

	if s.isRunning {
		log.Println("持续挖矿已在运行中")
		return nil
	}

	s.isRunning = true
	s.isPaused = false
	s.stopChan = make(chan struct{})

	log.Println("启动持续挖矿...")
	go s.run()

	return nil
}

// Stop 停止持续挖矿
func (s *SustainMiner) Stop() {
	s.mu.Lock()
	defer s.mu.Unlock()

	if !s.isRunning {
		return
	}

	log.Println("停止持续挖矿...")
	close(s.stopChan)
	s.isRunning = false

	// 停止当前挖矿进程
	if s.currentProcess != nil && s.currentProcess.Process != nil {
		log.Println("停止当前挖矿进程...")
		if runtime.GOOS == "linux" && s.config.Miner == "rigel" {
			// Linux rigel 使用 Interrupt 信号
			s.currentProcess.Process.Signal(os.Interrupt)
		} else {
			s.currentProcess.Process.Kill()
		}
		s.currentProcess = nil
	}
}

// Pause 暂停持续挖矿（当有新任务时调用）
func (s *SustainMiner) Pause() {
	s.mu.Lock()
	defer s.mu.Unlock()

	if !s.isRunning || s.isPaused {
		return
	}

	log.Println("暂停持续挖矿（有新任务）...")
	s.isPaused = true

	// 停止当前挖矿进程
	if s.currentProcess != nil && s.currentProcess.Process != nil {
		if runtime.GOOS == "linux" && s.config.Miner == "rigel" {
			s.currentProcess.Process.Signal(os.Interrupt)
		} else {
			s.currentProcess.Process.Kill()
		}
		s.currentProcess = nil
	}
}

// Resume 恢复持续挖矿（当任务结束后调用）
func (s *SustainMiner) Resume() {
	s.mu.Lock()
	defer s.mu.Unlock()

	if !s.isRunning || !s.isPaused {
		return
	}

	log.Println("恢复持续挖矿...")
	s.isPaused = false

	// 重新启动挖矿
	go s.startMining()
}

// run 持续挖矿主循环
func (s *SustainMiner) run() {
	for {
		select {
		case <-s.stopChan:
			log.Println("持续挖矿已停止")
			return
		default:
			s.mu.Lock()
			paused := s.isPaused
			s.mu.Unlock()

			if !paused {
				s.startMining()
				// 等待挖矿进程结束（正常情况下不会结束，除非被停止）
				if s.currentProcess != nil {
					s.currentProcess.Wait()
				}
			} else {
				// 如果被暂停，等待恢复
				time.Sleep(1 * time.Second)
			}
		}
	}
}

// startMining 启动挖矿进程
func (s *SustainMiner) startMining() {
	s.mu.Lock()
	defer s.mu.Unlock()

	if s.isPaused {
		return
	}

	var cmd *exec.Cmd
	var err error

	address := s.config.Wallet
	if !s.config.WalletMining && s.config.PoolUser != "" {
		address = s.config.PoolUser
	}

	switch strings.ToLower(s.config.Miner) {
	case "lolminer":
		cmd, err = s.startLolMiner(address)
	case "bzminer":
		cmd, err = s.startBzMiner(address)
	case "rigel":
		cmd, err = s.startRigel(address)
	default:
		log.Printf("不支持的挖矿软件: %s", s.config.Miner)
		return
	}

	if err != nil {
		log.Printf("启动持续挖矿失败: %v", err)
		return
	}

	s.currentProcess = cmd
	log.Printf("持续挖矿已启动: %s (PID: %d)", s.config.Miner, cmd.Process.Pid)
}

// startLolMiner 启动 lolminer
func (s *SustainMiner) startLolMiner(address string) (*exec.Cmd, error) {
	dir := s.miningConfig.LolMinerPath
	var name string
	if runtime.GOOS == "windows" {
		name = filepath.Join(dir, "lolMiner.exe")
	} else {
		name = filepath.Join(dir, "lolMiner")
	}

	args := []string{"--algo", s.config.Coin, "--pool", s.config.PoolUrl, "--user", address + "." + s.config.WorkerID}
	cmd := exec.Command(name, args...)
	cmd.Dir = dir
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	log.Printf("启动持续挖矿 lolminer: %s %s", name, strings.Join(args, " "))
	err := cmd.Start()
	return cmd, err
}

// startBzMiner 启动 bzminer
func (s *SustainMiner) startBzMiner(address string) (*exec.Cmd, error) {
	dir := s.miningConfig.BzMinerPath
	var name string
	if runtime.GOOS == "windows" {
		name = filepath.Join(dir, "bzminer.exe")
	} else {
		name = filepath.Join(dir, "bzminer")
	}

	args := []string{"-a", s.config.Coin, "-w", address + "." + s.config.WorkerID, "-p", s.config.PoolUrl}
	cmd := exec.Command(name, args...)
	cmd.Dir = dir
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	log.Printf("启动持续挖矿 bzminer: %s %s", name, strings.Join(args, " "))
	err := cmd.Start()
	return cmd, err
}

// startRigel 启动 rigel
func (s *SustainMiner) startRigel(address string) (*exec.Cmd, error) {
	dir := s.miningConfig.RigelPath
	var name string
	if runtime.GOOS == "windows" {
		name = filepath.Join(dir, "rigel.exe")
	} else {
		name = filepath.Join(dir, "rigel")
	}

	args := []string{"--no-watchdog", "-a", strings.ToLower(s.config.Algo), "-o", s.config.PoolUrl, "-u", address, "-w", s.config.WorkerID, "--log-file", "logs/miner.log"}
	cmd := exec.Command(name, args...)
	cmd.Dir = dir
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	log.Printf("启动持续挖矿 rigel: %s %s", name, strings.Join(args, " "))
	err := cmd.Start()
	return cmd, err
}

// IsRunning 检查是否正在运行
func (s *SustainMiner) IsRunning() bool {
	s.mu.Lock()
	defer s.mu.Unlock()
	return s.isRunning && !s.isPaused
}

// IsPaused 检查是否被暂停
func (s *SustainMiner) IsPaused() bool {
	s.mu.Lock()
	defer s.mu.Unlock()
	return s.isPaused
}
