package kbgovernance

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

// PublicationSnapshot is the complete immutable KB revision reviewed by one
// publication Approval. It is a transport-neutral governance value, not a
// persistence model or browser DTO.
type PublicationSnapshot struct {
	KnowledgeBaseID string                      `json:"knowledgeBaseId"`
	WorkingRevision string                      `json:"workingRevision"`
	IsActive        bool                        `json:"isActive"`
	Name            string                      `json:"name"`
	Description     string                      `json:"description"`
	GroupID         string                      `json:"groupId"`
	TagIDs          []string                    `json:"tagIds"`
	Sources         []PublicationSnapshotSource `json:"sources"`
}

// PublicationSnapshotSource is one source bound into a publication snapshot.
type PublicationSnapshotSource struct {
	ID                   string `json:"id"`
	SourceType           string `json:"sourceType"`
	Name                 string `json:"name"`
	Description          string `json:"description"`
	DefaultRef           string `json:"defaultRef"`
	IndexingMode         string `json:"indexingMode"`
	Status               string `json:"status"`
	SyncStatus           string `json:"syncStatus"`
	IndexStatus          string `json:"indexStatus"`
	Config               string `json:"config"`
	RevisionID           string `json:"revisionId"`
	SourceCommitSHA      string `json:"sourceCommitSha"`
	WikiRevision         string `json:"wikiRevision"`
	DashboardRevision    string `json:"dashboardRevision"`
	WikiDisposition      string `json:"wikiDisposition"`
	DashboardDisposition string `json:"dashboardDisposition"`
}

// EncodePublicationSnapshot returns the canonical bytes and digest used by the
// publication freshness fence. Tag IDs are sorted without mutating the caller.
func EncodePublicationSnapshot(snapshot PublicationSnapshot) ([]byte, string, error) {
	snapshot.TagIDs = append([]string(nil), snapshot.TagIDs...)
	sort.Strings(snapshot.TagIDs)
	encoded, err := json.Marshal(snapshot)
	if err != nil {
		return nil, "", fmt.Errorf("encode publication snapshot: %w", err)
	}
	digest := sha256.Sum256(encoded)
	return encoded, hex.EncodeToString(digest[:]), nil
}

// DecodePublicationSnapshot decodes one stored canonical publication snapshot.
func DecodePublicationSnapshot(encoded []byte) (PublicationSnapshot, error) {
	var snapshot PublicationSnapshot
	if err := json.Unmarshal(encoded, &snapshot); err != nil {
		return PublicationSnapshot{}, fmt.Errorf("decode publication snapshot: %w", err)
	}
	return snapshot, nil
}
