//go:build windows

package runtimecredential

import (
	"context"
	"errors"
	"fmt"
	"os"
	"syscall"
	"time"

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

func replaceCredentialFile(source, target string) error {
	sourcePath, err := syscall.UTF16PtrFromString(source)
	if err != nil {
		return err
	}
	targetPath, err := syscall.UTF16PtrFromString(target)
	if err != nil {
		return err
	}
	return windows.MoveFileEx(
		sourcePath,
		targetPath,
		windows.MOVEFILE_REPLACE_EXISTING|windows.MOVEFILE_WRITE_THROUGH,
	)
}

func removeCredentialTree(path string) error {
	const (
		retryInterval = 10 * time.Millisecond
		retryWindow   = 2 * time.Second
	)
	retryCtx, cancelRetry := context.WithTimeout(context.Background(), retryWindow)
	defer cancelRetry()
	for {
		// os.RemoveAll uses Lstat semantics for directory entries: symlinks are
		// removed rather than traversed. It may partially clean a tree before a
		// Windows sharing handle blocks one entry, so retry the whole owner-
		// managed tree until the transient window elapses.
		err := os.RemoveAll(path)
		if err == nil || errors.Is(err, os.ErrNotExist) {
			return err
		}
		if !errors.Is(err, windows.ERROR_SHARING_VIOLATION) &&
			!errors.Is(err, windows.ERROR_ACCESS_DENIED) {
			return err
		}
		timer := time.NewTimer(retryInterval)
		select {
		case <-timer.C:
		case <-retryCtx.Done():
			if !timer.Stop() {
				select {
				case <-timer.C:
				default:
				}
			}
			return err
		}
	}
}

func syncCredentialDirectory(string) error {
	return nil
}

func validatePrivateCredentialFile(_ string, info os.FileInfo) error {
	if !info.Mode().IsRegular() || info.Mode()&os.ModeSymlink != 0 {
		return fmt.Errorf("credential is not a regular file")
	}
	return nil
}
