//go:build windows

package sboxrun

import (
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"os"
	"path/filepath"
	"strings"
)

// AssetPaths records where the binaries landed after install.
type AssetPaths struct {
	SingBoxExe string
	WintunDLL  string
	WorkDir    string // %PROGRAMDATA%\Drover\sboxrun
	ConfigPath string // <workdir>\config.json
	LogPath    string // <workdir>\sing-box.log
}

// InstallAssets extracts sing-box.exe + wintun.dll into
// %PROGRAMDATA%\Drover\sboxrun\ (creating the directory if needed)
// and verifies SHA256. Idempotent — second runs skip if existing
// files match the embedded SHAs.
func InstallAssets() (*AssetPaths, error) {
	pd := os.Getenv("ProgramData")
	if pd == "" {
		return nil, fmt.Errorf("ProgramData environment variable is not set")
	}
	dir := filepath.Join(pd, "Drover", "sboxrun")
	if err := os.MkdirAll(dir, 0755); err != nil {
		return nil, fmt.Errorf("create %s: %w", dir, err)
	}

	exePath := filepath.Join(dir, "sing-box.exe")
	dllPath := filepath.Join(dir, "wintun.dll")

	if err := writeIfDifferent(exePath, singBoxExe, SingBoxSHA256); err != nil {
		return nil, fmt.Errorf("install sing-box.exe: %w", err)
	}
	if err := writeIfDifferent(dllPath, wintunDLL, WintunSHA256); err != nil {
		return nil, fmt.Errorf("install wintun.dll: %w", err)
	}

	return &AssetPaths{
		SingBoxExe: exePath,
		WintunDLL:  dllPath,
		WorkDir:    dir,
		ConfigPath: filepath.Join(dir, "config.json"),
		LogPath:    filepath.Join(dir, "sing-box.log"),
	}, nil
}

func writeIfDifferent(path string, content []byte, expectedSHA string) error {
	if existing, err := os.ReadFile(path); err == nil {
		if strings.EqualFold(sha256Hex(existing), expectedSHA) {
			return nil
		}
	}
	tmp := path + ".new"
	if err := os.WriteFile(tmp, content, 0644); err != nil {
		return err
	}
	if err := os.Rename(tmp, path); err != nil {
		_ = os.Remove(tmp)
		return err
	}
	got, err := os.ReadFile(path)
	if err != nil {
		return err
	}
	if !strings.EqualFold(sha256Hex(got), expectedSHA) {
		return fmt.Errorf("SHA256 mismatch after write at %s; antivirus may have tampered with the file. Add %%PROGRAMDATA%%\\Drover\\ to AV exclusions", path)
	}
	return nil
}

func sha256Hex(b []byte) string {
	h := sha256.Sum256(b)
	return hex.EncodeToString(h[:])
}
