package repos

import (
	"crypto/sha256"
	"encoding/hex"
	"strings"
	"time"
)

const (
	ResourceTypeMemory               = "memory"
	ResourceTypeSkillRepository      = "skill_repository"
	ResourceTypeKBSource             = "kb_source"
	ResourceTypeAutomationRepository = "automation_repository"

	// RepoRolePrimary names the primary repository's semantic role. Its
	// persisted and client-visible spelling is frozen for compatibility.
	RepoRolePrimary  = "canonical"
	RepoRoleMirror   = "mirror"
	RepoRoleInsights = "insights"
)

const (
	AccessIntentTypeKBGrant     = "kb_grant"
	AccessIntentTypeMemoryGrant = "memory_grant"

	AccessPermissionRead  = "read"
	AccessPermissionWrite = "write"
	AccessPermissionAdmin = "admin"

	AccessStatusPending = "pending"
	AccessStatusCurrent = "current"
	AccessStatusBlocked = "blocked"
	AccessStatusRevoked = "revoked"
)

// ResourceRepository is the persisted mapping from a resource-runtime asset to
// an embedded AGS repository that has already been ensured to exist. It is not
// a AgentTeam server repository/project model, an AGS repository record, or an API
// DTO; it stores only the resource owner's binding and presentation metadata.
type ResourceRepository struct {
	ID           string    `gorm:"primaryKey;size:64"`
	WorkspaceID  string    `gorm:"size:64;not null;index:idx_resource_repositories_resource;uniqueIndex:uk_resource_repository_role"`
	ResourceType string    `gorm:"size:64;not null;index:idx_resource_repositories_resource;index:idx_resource_repositories_type_resource_role,priority:1;uniqueIndex:uk_resource_repository_role"`
	ResourceID   string    `gorm:"size:64;not null;index:idx_resource_repositories_resource;index:idx_resource_repositories_type_resource_role,priority:2;uniqueIndex:uk_resource_repository_role"`
	RepoRole     string    `gorm:"size:64;not null;index:idx_resource_repositories_type_resource_role,priority:3;uniqueIndex:uk_resource_repository_role"`
	OwnerKind    string    `gorm:"size:64;not null"`
	RepoOwner    string    `gorm:"size:128;not null"`
	RepoName     string    `gorm:"size:128;not null"`
	RepoFullName string    `gorm:"size:255;not null;index"`
	AGSRepoID    string    `gorm:"column:ags_repo_id;size:64;not null;default:'';index"`
	DefaultRef   string    `gorm:"size:255;not null;default:''"`
	Visibility   string    `gorm:"size:64;not null;default:'private'"`
	UserVisible  bool      `gorm:"not null;default:false"`
	CreatedBy    string    `gorm:"size:64;not null"`
	UpdatedBy    string    `gorm:"size:64;not null"`
	CreatedAt    time.Time `gorm:"not null"`
	UpdatedAt    time.Time `gorm:"not null;index"`
}

func (ResourceRepository) TableName() string { return "resource_repositories" }

const (
	ResourceRepositoryLifecycleOperationCreateBind    = "create_bind"
	ResourceRepositoryLifecycleOperationDelete        = "delete"
	ResourceRepositoryLifecycleOperationDeleteCleanup = "delete_cleanup"

	ResourceRepositoryLifecycleStatusPending   = "pending"
	ResourceRepositoryLifecycleStatusSucceeded = "succeeded"
	ResourceRepositoryLifecycleStatusFailed    = "failed"
)

// ResourceRepositoryLifecycleEvent is the resource runtime's persisted
// compensation ledger for cross-system repository lifecycle attempts. Embedded
// AGS is mutated through its API; this row records enough binding and failure
// state to reconcile an incomplete create/delete operation. It is not a AgentTeam
// audit event, resource activity event, or generic workflow job.
type ResourceRepositoryLifecycleEvent struct {
	ID           string    `gorm:"primaryKey;size:64"`
	WorkspaceID  string    `gorm:"size:64;not null;index:idx_resource_repo_lifecycle_resource"`
	ResourceType string    `gorm:"size:64;not null;index:idx_resource_repo_lifecycle_resource"`
	ResourceID   string    `gorm:"size:64;not null;index:idx_resource_repo_lifecycle_resource"`
	RepoRole     string    `gorm:"size:64;not null"`
	RepoOwner    string    `gorm:"size:128;not null"`
	RepoName     string    `gorm:"size:128;not null"`
	RepoFullName string    `gorm:"size:255;not null;index"`
	AGSRepoID    string    `gorm:"column:ags_repo_id;size:64;not null;default:''"`
	Operation    string    `gorm:"size:64;not null;index:idx_resource_repo_lifecycle_status"`
	Status       string    `gorm:"size:32;not null;index:idx_resource_repo_lifecycle_status"`
	LastError    string    `gorm:"type:text;not null"`
	CreatedBy    string    `gorm:"size:64;not null"`
	UpdatedBy    string    `gorm:"size:64;not null"`
	CreatedAt    time.Time `gorm:"not null"`
	UpdatedAt    time.Time `gorm:"not null;index"`
}

func (ResourceRepositoryLifecycleEvent) TableName() string {
	return "resource_repository_lifecycle_events"
}

// ResourceRepositoryAccessGrant is the resource runtime's persisted desired
// collaborator intent and latest embedded AGS materialization state for one
// resource repository. It is not AgentTeam workspace membership, a generic
// authorization policy, or an API grant DTO; AgentTeam identity and membership facts
// remain owned by their respective control-plane domains.
type ResourceRepositoryAccessGrant struct {
	ID               string     `gorm:"primaryKey;size:64"`
	WorkspaceID      string     `gorm:"size:64;not null;index:idx_resource_repo_access_subject;index:idx_resource_repo_access_repo_subject,priority:1;index:idx_resource_repo_access_intent_lookup,priority:1;uniqueIndex:uk_resource_repo_access_intent"`
	ResourceType     string     `gorm:"size:64;not null;index:idx_resource_repo_access_resource;uniqueIndex:uk_resource_repo_access_intent"`
	ResourceID       string     `gorm:"size:64;not null;index:idx_resource_repo_access_resource;uniqueIndex:uk_resource_repo_access_intent"`
	RepoRole         string     `gorm:"size:64;not null;uniqueIndex:uk_resource_repo_access_intent"`
	RepoFullName     string     `gorm:"size:255;not null;index;index:idx_resource_repo_access_repo_subject,priority:2"`
	AGSRepoID        string     `gorm:"column:ags_repo_id;size:64;not null;default:''"`
	SubjectType      string     `gorm:"size:32;not null;index:idx_resource_repo_access_subject;index:idx_resource_repo_access_repo_subject,priority:3;uniqueIndex:uk_resource_repo_access_intent"`
	SubjectID        string     `gorm:"size:64;not null;index:idx_resource_repo_access_subject;index:idx_resource_repo_access_repo_subject,priority:4;uniqueIndex:uk_resource_repo_access_intent"`
	Permission       string     `gorm:"size:32;not null;default:'read'"`
	IntentType       string     `gorm:"size:64;not null;index:idx_resource_repo_access_intent_lookup,priority:2;uniqueIndex:uk_resource_repo_access_intent"`
	IntentID         string     `gorm:"size:64;not null;index:idx_resource_repo_access_intent_lookup,priority:3;uniqueIndex:uk_resource_repo_access_intent"`
	IntentProfile    string     `gorm:"size:32;not null;default:''"`
	Materialized     bool       `gorm:"not null;default:false"`
	Status           string     `gorm:"size:32;not null;default:'pending';index:idx_resource_repo_access_status"`
	LastError        string     `gorm:"type:text;not null"`
	CreatedBy        string     `gorm:"size:64;not null"`
	UpdatedBy        string     `gorm:"size:64;not null"`
	ReconciledBy     string     `gorm:"size:64;not null;default:''"`
	RevokedBy        string     `gorm:"size:64;not null;default:''"`
	CreatedAt        time.Time  `gorm:"not null"`
	UpdatedAt        time.Time  `gorm:"not null;index"`
	LastReconciledAt *time.Time `gorm:"index"`
	RevokedAt        *time.Time `gorm:"index"`
}

func AutomationRepositoryResourceID(repoFullName string) string {
	sum := sha256.Sum256([]byte(strings.ToLower(strings.TrimSpace(repoFullName))))
	return hex.EncodeToString(sum[:])
}

func ResourceRepositoryBindingID(workspaceID, resourceType, resourceID, repoRole string) string {
	sum := sha256.Sum256([]byte(strings.TrimSpace(workspaceID) + "\x00" + strings.TrimSpace(resourceType) + "\x00" + strings.TrimSpace(resourceID) + "\x00" + strings.TrimSpace(repoRole)))
	return hex.EncodeToString(sum[:])
}

func ResourceRepositoryAccessGrantID(workspaceID, resourceType, resourceID, repoRole, subjectType, subjectID, intentType, intentID string) string {
	sum := sha256.Sum256([]byte(strings.TrimSpace(workspaceID) + "\x00" + strings.TrimSpace(resourceType) + "\x00" + strings.TrimSpace(resourceID) + "\x00" + strings.TrimSpace(repoRole) + "\x00" + strings.TrimSpace(subjectType) + "\x00" + strings.TrimSpace(subjectID) + "\x00" + strings.TrimSpace(intentType) + "\x00" + strings.TrimSpace(intentID)))
	return hex.EncodeToString(sum[:])
}
