package serviceaccount

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"

	serviceaccountstore "github.com/tidbcloud/AgentTeam/internal/store/serviceaccount"
)

const (
	materializationReceiptVersion = 1
	receiptDigestAlgorithm        = "sha256"
	reconcileStatePending         = "pending"
)

// materializationReceipt is the immutable logical input fence for one local
// Service Account identity. It records normalized caller input, including
// whether each identity ref was explicitly supplied. Generated refs are kept
// out of the receipt so a retry that omitted them remains equivalent.
//
// Now and CorrelationID are deliberately excluded: they describe one execution
// attempt rather than the logical materialization requested by the caller.
type materializationReceipt struct {
	Version   int                                     `json:"version"`
	Kind      string                                  `json:"kind"`
	Workspace *workspaceMaterializationReceiptPayload `json:"workspace,omitempty"`
	Platform  *platformMaterializationReceiptPayload  `json:"platform,omitempty"`
}

type materializationIdentityReceipt struct {
	AccountID             string `json:"accountId"`
	ServiceInstallationID string `json:"serviceInstallationId"`
	ServiceMemberID       string `json:"serviceMemberId"`
	AuthorMemberID        string `json:"authorMemberId"`
	MessageScopeID        string `json:"messageScopeId"`
	NameClaimID           string `json:"nameClaimId"`
	PlatformInstanceID    string `json:"platformInstanceId"`
}

type workspaceMaterializationReceiptPayload struct {
	Identity          materializationIdentityReceipt `json:"identity"`
	WorkspaceID       string                         `json:"workspaceId"`
	CreatorMemberID   string                         `json:"creatorMemberId"`
	Name              string                         `json:"name"`
	Description       string                         `json:"description"`
	AvatarAssetID     string                         `json:"avatarAssetId"`
	AvatarURL         string                         `json:"avatarUrl"`
	ManagerMemberIDs  []string                       `json:"managerMemberIds"`
	AuthorizationPath string                         `json:"authorizationPath"`
}

type platformMaterializationReceiptPayload struct {
	Identity                     materializationIdentityReceipt `json:"identity"`
	WorkspaceID                  string                         `json:"workspaceId"`
	PlatformServiceAccountID     string                         `json:"platformServiceAccountId"`
	OperatorUserID               string                         `json:"operatorUserId"`
	AvatarURL                    string                         `json:"avatarUrl"`
	OpenedProvisioningGeneration int64                          `json:"openedProvisioningGeneration"`
}

type materializationAuditRecord struct {
	DigestAlgorithm string                 `json:"digestAlgorithm"`
	Digest          string                 `json:"digest"`
	Receipt         materializationReceipt `json:"receipt"`
}

// materializationReconcileIntent durably hands the intentionally unfinished
// audience/provisioning projections to a later reconciler. Creation persists
// this intent while the authoritative rows remain pending.
type materializationReconcileIntent struct {
	Audience             audienceReconcileIntent              `json:"audience"`
	PlatformProvisioning *platformProvisioningReconcileIntent `json:"platformProvisioning,omitempty"`
}

type audienceReconcileIntent struct {
	State         string `json:"state"`
	PolicyVersion int64  `json:"policyVersion"`
}

type platformProvisioningReconcileIntent struct {
	State                         string `json:"state"`
	PlatformServiceAccountID      string `json:"platformServiceAccountId"`
	PlatformWorkspaceInstanceID   string `json:"platformWorkspaceInstanceId"`
	OpenedProvisioningGeneration  int64  `json:"openedProvisioningGeneration"`
	EffectiveFromBroadcastSeq     int64  `json:"effectiveFromBroadcastSeq"`
	LastAppliedBroadcastSeq       int64  `json:"lastAppliedBroadcastSeq"`
	AppliedPlatformProfileVersion int64  `json:"appliedPlatformProfileVersion"`
}

type createdAuditMetadata struct {
	AuthorMemberID        string                         `json:"authorMemberId"`
	ServiceInstallationID string                         `json:"serviceInstallationId"`
	ServiceMemberID       string                         `json:"serviceMemberId"`
	MessageScopeID        string                         `json:"messageScopeId"`
	Materialization       materializationAuditRecord     `json:"materialization"`
	ReconcileIntent       materializationReconcileIntent `json:"reconcileIntent"`
}

func newWorkspaceMaterializationReceipt(input WorkspaceMaterialization, callerIdentity IdentityRefs, name string, managers []string) materializationReceipt {
	return materializationReceipt{
		Version: materializationReceiptVersion,
		Kind:    serviceaccountstore.ManagementKindWorkspace,
		Workspace: &workspaceMaterializationReceiptPayload{
			Identity:          identityReceipt(callerIdentity),
			WorkspaceID:       input.WorkspaceID,
			CreatorMemberID:   input.CreatorMemberID,
			Name:              name,
			Description:       input.Description,
			AvatarAssetID:     input.AvatarAssetID,
			AvatarURL:         input.AvatarURL,
			ManagerMemberIDs:  managers,
			AuthorizationPath: input.AuthorizationPath,
		},
	}
}

func newPlatformMaterializationReceipt(input PlatformInstanceMaterialization, callerIdentity IdentityRefs) materializationReceipt {
	return materializationReceipt{
		Version: materializationReceiptVersion,
		Kind:    serviceaccountstore.ManagementKindPlatform,
		Platform: &platformMaterializationReceiptPayload{
			Identity:                     identityReceipt(callerIdentity),
			WorkspaceID:                  input.WorkspaceID,
			PlatformServiceAccountID:     input.PlatformServiceAccountID,
			OperatorUserID:               input.OperatorUserID,
			AvatarURL:                    input.AvatarURL,
			OpenedProvisioningGeneration: input.OpenedProvisioningGeneration,
		},
	}
}

func identityReceipt(refs IdentityRefs) materializationIdentityReceipt {
	return materializationIdentityReceipt{
		AccountID:             refs.AccountID,
		ServiceInstallationID: refs.ServiceInstallationID,
		ServiceMemberID:       refs.ServiceMemberID,
		AuthorMemberID:        refs.AuthorMemberID,
		MessageScopeID:        refs.MessageScopeID,
		NameClaimID:           refs.NameClaimID,
		PlatformInstanceID:    refs.PlatformInstanceID,
	}
}

func digestMaterializationReceipt(receipt materializationReceipt) (string, error) {
	encoded, err := json.Marshal(receipt)
	if err != nil {
		return "", fmt.Errorf("marshal service account materialization receipt: %w", err)
	}
	sum := sha256.Sum256(encoded)
	return hex.EncodeToString(sum[:]), nil
}
