//go:build windows

package runtimecredential

import (
	"os"
	"testing"
	"unsafe"

	"github.com/stretchr/testify/require"
	"golang.org/x/sys/windows"

	"github.com/tidbcloud/AgentTeam/desktop/internal/profile"
)

const windowsFileAllAccess windows.ACCESS_MASK = windows.STANDARD_RIGHTS_REQUIRED | windows.SYNCHRONIZE | 0x1ff

func TestCredentialWindowsSharingReplacementCleanupAndProtectedDACL(t *testing.T) {
	t.Setenv(profile.ConfigDirEnvKey, t.TempDir())
	credential, err := Create("old-token")
	require.NoError(t, err)
	path := credential.Path()
	assertCredentialWindowsProtectedDACL(t, path)

	reader, err := os.Open(path)
	require.NoError(t, err)
	replaceErr := credential.Replace("new-token")
	if replaceErr != nil {
		// A sharing violation is a publication failure: the visible file must
		// remain the complete predecessor until a later retry succeeds.
		assertCredentialValue(t, path, "old-token")
	}
	require.NoError(t, reader.Close())
	if replaceErr != nil {
		require.NoError(t, credential.Replace("new-token"))
	}
	assertCredentialValue(t, path, "new-token")
	assertCredentialWindowsProtectedDACL(t, path)

	reader, err = os.Open(path)
	require.NoError(t, err)
	closeErr := credential.Close()
	require.NoError(t, reader.Close())
	if closeErr != nil {
		// Close prevents all future Replace calls but permits cleanup retry after
		// a transient sharing violation releases its handle.
		require.NoError(t, credential.Close())
	}
	require.NoFileExists(t, path)
}

func assertCredentialWindowsProtectedDACL(t *testing.T, path string) {
	t.Helper()
	descriptor, err := windows.GetNamedSecurityInfo(
		path,
		windows.SE_FILE_OBJECT,
		windows.DACL_SECURITY_INFORMATION,
	)
	require.NoError(t, err)
	control, _, err := descriptor.Control()
	require.NoError(t, err)
	require.NotZero(t, control&windows.SE_DACL_PROTECTED)
	dacl, _, err := descriptor.DACL()
	require.NoError(t, err)
	require.NotNil(t, dacl)

	currentUser, err := windows.GetCurrentProcessToken().GetTokenUser()
	require.NoError(t, err)
	systemSID, err := windows.CreateWellKnownSid(windows.WinLocalSystemSid)
	require.NoError(t, err)
	allowed := map[string]bool{
		currentUser.User.Sid.String(): false,
		systemSID.String():            false,
	}
	require.Equal(t, len(allowed), int(dacl.AceCount))
	for index := uint32(0); index < uint32(dacl.AceCount); index++ {
		var ace *windows.ACCESS_ALLOWED_ACE
		require.NoError(t, windows.GetAce(dacl, index, &ace))
		require.Equal(t, uint8(windows.ACCESS_ALLOWED_ACE_TYPE), ace.Header.AceType)
		require.Zero(t, ace.Header.AceFlags&(windows.INHERITED_ACE|windows.OBJECT_INHERIT_ACE|windows.CONTAINER_INHERIT_ACE))
		require.True(t, ace.Mask == windows.GENERIC_ALL || ace.Mask == windowsFileAllAccess)
		sid := (*windows.SID)(unsafe.Pointer(&ace.SidStart)).String()
		_, ok := allowed[sid]
		require.True(t, ok)
		allowed[sid] = true
	}
	for _, present := range allowed {
		require.True(t, present)
	}
}
