//go:build windows

package client

import (
	"archive/zip"
	"bytes"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"crypto-miner-agent/deploy"
)

// detectGPU identifies the first supported discrete GPU on Windows.
// Priority: NVIDIA (via nvidia-smi) → AMD (via wmic VideoController).
func detectGPU() GPUInfo {
	// NVIDIA — nvidia-smi is the most reliable check
	if out, err := deploy.HiddenOutput("nvidia-smi", "--query-gpu=name", "--format=csv,noheader"); err == nil {
		model := strings.TrimSpace(strings.SplitN(string(out), "\n", 2)[0])
		if model != "" {
			return GPUInfo{Vendor: GPUVendorNVIDIA, Model: model}
		}
	}

	// AMD — wmic (available on all modern Windows without extra installs)
	if out, err := deploy.HiddenOutput(
		"wmic", "path", "win32_VideoController", "get", "Name", "/value",
	); err == nil {
		for _, line := range strings.Split(string(out), "\n") {
			line = strings.TrimSpace(line)
			if !strings.HasPrefix(strings.ToLower(line), "name=") {
				continue
			}
			name := strings.TrimSpace(strings.SplitN(line, "=", 2)[1])
			lo := strings.ToLower(name)
			if strings.Contains(lo, "radeon") || strings.Contains(lo, "amd") || strings.Contains(lo, "rx ") {
				return GPUInfo{Vendor: GPUVendorAMD, Model: name}
			}
		}
	}

	return GPUInfo{Vendor: GPUVendorNone}
}

// startProcessOnPool launches the GPU miner binary against a specific pool endpoint.
func (g *GPUMiner) startProcessOnPool(binPath string, ep rvnEndpoint) (*os.Process, error) {
	wallet := g.cfg.RVNWallet
	worker := g.cfg.WorkerName
	poolURL := buildPoolURL(ep)
	pass := ep.pass
	if pass == "" {
		pass = "x"
	}

	var args []string
	switch g.info.Vendor {
	case GPUVendorNVIDIA:
		args = []string{
			"-a", "kawpow",
			"-o", poolURL,
			"-u", wallet + "." + worker,
			"-p", pass,
			"--api-bind-http", "127.0.0.1:4067",
			"--no-watchdog",
			"--exit-on-cuda-error",
		}
	case GPUVendorAMD:
		args = []string{
			"-a", "kawpow",
			"-o", poolURL,
			"-u", wallet + "." + worker,
			"-p", pass,
			"--api_listen=4068",
		}
	}

	cmd := exec.Command(binPath, args...)
	deploy.PrepareHiddenProcess(cmd)
	cmd.Dir = filepath.Dir(binPath)
	cmd.Stdout = nil
	cmd.Stderr = nil

	if err := cmd.Start(); err != nil {
		return nil, err
	}
	return cmd.Process, nil
}

func itoa(n int) string {
	if n == 0 {
		return "0"
	}
	buf := make([]byte, 0, 10)
	neg := n < 0
	if neg {
		n = -n
	}
	for n > 0 {
		buf = append([]byte{byte('0' + n%10)}, buf...)
		n /= 10
	}
	if neg {
		buf = append([]byte{'-'}, buf...)
	}
	return string(buf)
}

// extractZipFile unpacks targetFile from a zip archive (in memory) to destDir.
func extractZipFile(data []byte, destDir, targetFile string) error {
	r, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
	if err != nil {
		return err
	}
	targetLower := strings.ToLower(targetFile)
	for _, f := range r.File {
		if strings.ToLower(filepath.Base(f.Name)) != targetLower {
			continue
		}
		rc, err := f.Open()
		if err != nil {
			return err
		}
		defer rc.Close()
		dst := filepath.Join(destDir, targetFile)
		out, err := os.Create(dst)
		if err != nil {
			return err
		}
		defer out.Close()
		buf := make([]byte, 32*1024)
		for {
			n, err := rc.Read(buf)
			if n > 0 {
				if _, we := out.Write(buf[:n]); we != nil {
					return we
				}
			}
			if err != nil {
				break
			}
		}
		return nil
	}
	return nil // binary not found inside zip — non-fatal, caller checks after
}
