//go:build windows

package daemoncontrol

import (
	"errors"
	"fmt"
	"os"
	"syscall"
	"unsafe"

	"github.com/tidbcloud/AgentTeam/desktop/internal/profile"
	"golang.org/x/sys/windows"
)

// Windows maps GENERIC_ALL on file objects to FILE_ALL_ACCESS when it stores
// the ACE. x/sys does not currently expose FILE_ALL_ACCESS.
const fileAllAccess windows.ACCESS_MASK = windows.STANDARD_RIGHTS_REQUIRED | windows.SYNCHRONIZE | 0x1ff

func secureRuntimeFile(path string) error {
	return profile.SecureRuntimeFile(path)
}

func ensurePrivateRuntimeDir(path string) error {
	if err := os.MkdirAll(path, 0o700); err != nil {
		return err
	}
	return profile.SecureRuntimeFile(path)
}

func validatePrivateRuntimeFile(path string, _ os.FileInfo) error {
	descriptor, err := windows.GetNamedSecurityInfo(
		path,
		windows.SE_FILE_OBJECT,
		windows.OWNER_SECURITY_INFORMATION|
			windows.GROUP_SECURITY_INFORMATION|
			windows.DACL_SECURITY_INFORMATION,
	)
	if err != nil {
		return fmt.Errorf("read DACL: %w", err)
	}
	if descriptor == nil {
		return fmt.Errorf("DACL is missing")
	}
	control, _, err := descriptor.Control()
	if err != nil {
		return fmt.Errorf("read DACL control: %w", err)
	}
	if control&windows.SE_DACL_PROTECTED == 0 {
		return fmt.Errorf("DACL is not protected")
	}
	// DACL reports absence as an error; its bool reports whether the ACL was
	// defaulted, not whether it is present.
	dacl, _, err := descriptor.DACL()
	if err != nil {
		return fmt.Errorf("read DACL entries: %w", err)
	}
	if dacl == nil {
		return fmt.Errorf("DACL is missing")
	}

	tokenUser, err := windows.GetCurrentProcessToken().GetTokenUser()
	if err != nil {
		return fmt.Errorf("get current user SID: %w", err)
	}
	systemSID, err := windows.CreateWellKnownSid(windows.WinLocalSystemSid)
	if err != nil {
		return fmt.Errorf("create SYSTEM SID: %w", err)
	}
	allowed := map[string]bool{
		tokenUser.User.Sid.String(): false,
		systemSID.String():          false,
	}
	if int(dacl.AceCount) != len(allowed) {
		return fmt.Errorf("DACL has unexpected ACE count")
	}
	for index := uint32(0); index < uint32(dacl.AceCount); index++ {
		var ace *windows.ACCESS_ALLOWED_ACE
		if err := windows.GetAce(dacl, index, &ace); err != nil {
			return fmt.Errorf("read DACL ACE: %w", err)
		}
		if ace.Header.AceType != windows.ACCESS_ALLOWED_ACE_TYPE ||
			ace.Header.AceFlags&(windows.INHERITED_ACE|windows.OBJECT_INHERIT_ACE|windows.CONTAINER_INHERIT_ACE) != 0 ||
			(ace.Mask != windows.GENERIC_ALL && ace.Mask != fileAllAccess) {
			return fmt.Errorf("DACL contains an unexpected ACE")
		}
		sid := (*windows.SID)(unsafe.Pointer(&ace.SidStart)).String()
		if _, ok := allowed[sid]; !ok {
			return fmt.Errorf("DACL grants an unexpected SID")
		}
		allowed[sid] = true
	}
	for _, found := range allowed {
		if !found {
			return fmt.Errorf("DACL omits an expected SID")
		}
	}
	return nil
}

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

func tryLockMutationFile(file *os.File) (bool, error) {
	var overlapped windows.Overlapped
	err := windows.LockFileEx(
		windows.Handle(file.Fd()),
		windows.LOCKFILE_EXCLUSIVE_LOCK|windows.LOCKFILE_FAIL_IMMEDIATELY,
		0,
		1,
		0,
		&overlapped,
	)
	if err == nil {
		return true, nil
	}
	if errors.Is(err, windows.ERROR_LOCK_VIOLATION) {
		return false, nil
	}
	return false, err
}

func unlockMutationFile(file *os.File) error {
	var overlapped windows.Overlapped
	return windows.UnlockFileEx(
		windows.Handle(file.Fd()),
		0,
		1,
		0,
		&overlapped,
	)
}

// Windows does not support opening a directory for FlushFileBuffers through
// os.File. The receipt file itself is synced before the atomic rename.
func syncDirectory(string) error {
	return nil
}
