//go:build windows

package main

import (
	"io"
	"os"
	"path/filepath"
	"strings"
)

func resolveWindowsWebviewUserDataPath() string {
	appDataDir := strings.TrimSpace(os.Getenv("APPDATA"))
	if appDataDir == "" {
		return ""
	}

	targetDir := filepath.Join(appDataDir, "GoNavi", "WebView2")
	_ = migrateLegacyWindowsWebviewUserData(appDataDir, targetDir)
	return targetDir
}

func migrateLegacyWindowsWebviewUserData(appDataDir, targetDir string) error {
	if dirHasContent(targetDir) {
		return nil
	}

	exeName := "GoNavi.exe"
	if exePath, err := os.Executable(); err == nil {
		base := strings.TrimSpace(filepath.Base(exePath))
		if base != "" {
			exeName = base
		}
	}
	exeBase := strings.TrimSuffix(exeName, filepath.Ext(exeName))

	candidates := []string{
		filepath.Join(appDataDir, exeName),
		filepath.Join(appDataDir, exeBase),
		filepath.Join(appDataDir, "GoNavi.exe"),
		filepath.Join(appDataDir, "GoNavi"),
	}

	seen := make(map[string]struct{}, len(candidates))
	for _, candidate := range candidates {
		src := filepath.Clean(strings.TrimSpace(candidate))
		if src == "" || strings.EqualFold(src, filepath.Clean(targetDir)) {
			continue
		}
		key := strings.ToLower(src)
		if _, exists := seen[key]; exists {
			continue
		}
		seen[key] = struct{}{}

		if !dirHasContent(src) {
			continue
		}
		return copyDirTree(src, targetDir)
	}
	return nil
}

func dirHasContent(path string) bool {
	info, err := os.Stat(path)
	if err != nil || !info.IsDir() {
		return false
	}
	entries, err := os.ReadDir(path)
	return err == nil && len(entries) > 0
}

func copyDirTree(srcDir, dstDir string) error {
	if err := os.MkdirAll(dstDir, 0o755); err != nil {
		return err
	}

	return filepath.WalkDir(srcDir, func(srcPath string, d os.DirEntry, walkErr error) error {
		if walkErr != nil {
			return walkErr
		}
		relPath, err := filepath.Rel(srcDir, srcPath)
		if err != nil {
			return err
		}
		if relPath == "." {
			return nil
		}
		dstPath := filepath.Join(dstDir, relPath)

		if d.IsDir() {
			return os.MkdirAll(dstPath, 0o755)
		}

		info, err := d.Info()
		if err != nil {
			return err
		}
		return copyFileWithMode(srcPath, dstPath, info.Mode())
	})
}

func copyFileWithMode(srcPath, dstPath string, mode os.FileMode) error {
	srcFile, err := os.Open(srcPath)
	if err != nil {
		return err
	}
	defer srcFile.Close()

	if err := os.MkdirAll(filepath.Dir(dstPath), 0o755); err != nil {
		return err
	}
	dstFile, err := os.OpenFile(dstPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, mode.Perm())
	if err != nil {
		return err
	}
	defer dstFile.Close()

	if _, err := io.Copy(dstFile, srcFile); err != nil {
		return err
	}
	return nil
}
