package access

import (
	"strings"
	"time"
)

const (
	CapabilityRead  = "repo:read"
	CapabilityClone = "repo:clone"
	CapabilityWrite = "repo:write"
)

// SyncLeaseRequest describes the common data needed to request an AGS
// repository sync token. Domain services adapt it to their issuer interface.
type SyncLeaseRequest struct {
	WorkspaceID      string
	ActorPrincipalID string
	ProviderHost     string
	Repositories     []string
	Capabilities     []string
	DisplayName      string
	ExpiresAt        *time.Time
}

// NewSyncLeaseRequest normalizes common fields and deduplicates repository
// full names without changing the domain-selected provider host or capabilities.
func NewSyncLeaseRequest(workspaceID, actorPrincipalID, providerHost, displayName string, repositories, capabilities []string) SyncLeaseRequest {
	return SyncLeaseRequest{
		WorkspaceID:      strings.TrimSpace(workspaceID),
		ActorPrincipalID: strings.TrimSpace(actorPrincipalID),
		ProviderHost:     strings.TrimSpace(providerHost),
		Repositories:     UniqueRepositoryFullNames(repositories),
		Capabilities:     uniqueTrimmed(capabilities),
		DisplayName:      strings.TrimSpace(displayName),
	}
}

// UniqueRepositoryFullNames returns stable, case-insensitive unique repository
// full names while preserving the first caller-provided spelling.
func UniqueRepositoryFullNames(values []string) []string {
	out := make([]string, 0, len(values))
	seen := make(map[string]struct{}, len(values))
	for _, value := range values {
		trimmed := strings.TrimSpace(value)
		if trimmed == "" {
			continue
		}
		key := strings.ToLower(trimmed)
		if _, ok := seen[key]; ok {
			continue
		}
		seen[key] = struct{}{}
		out = append(out, trimmed)
	}
	return out
}

func uniqueTrimmed(values []string) []string {
	out := make([]string, 0, len(values))
	seen := make(map[string]struct{}, len(values))
	for _, value := range values {
		trimmed := strings.TrimSpace(value)
		if trimmed == "" {
			continue
		}
		if _, ok := seen[trimmed]; ok {
			continue
		}
		seen[trimmed] = struct{}{}
		out = append(out, trimmed)
	}
	return out
}
