package kb

import (
	"fmt"
	"strings"
)

const kbSourceCutoverCheckpointPrefix = "kb1|"

type kbSourceCutoverCheckpoint struct {
	SourceContentVersionID string
	UADashboardVersionID   string
}

func encodeKBSourceCutoverCheckpoint(checkpoint kbSourceCutoverCheckpoint) (string, error) {
	checkpoint.SourceContentVersionID = strings.TrimSpace(checkpoint.SourceContentVersionID)
	checkpoint.UADashboardVersionID = strings.TrimSpace(checkpoint.UADashboardVersionID)
	if !validKBSourceCutoverVersionID(checkpoint.SourceContentVersionID) ||
		(checkpoint.UADashboardVersionID != "" && !validKBSourceCutoverVersionID(checkpoint.UADashboardVersionID)) {
		return "", fmt.Errorf("KB source cutover checkpoint is invalid")
	}
	encoded := kbSourceCutoverCheckpointPrefix + checkpoint.SourceContentVersionID + "|" + checkpoint.UADashboardVersionID
	if len(encoded) > 255 {
		return "", fmt.Errorf("KB source cutover checkpoint is too large")
	}
	return encoded, nil
}

func decodeKBSourceCutoverCheckpoint(value string) (kbSourceCutoverCheckpoint, error) {
	value = strings.TrimSpace(value)
	if !strings.HasPrefix(value, kbSourceCutoverCheckpointPrefix) {
		return kbSourceCutoverCheckpoint{}, fmt.Errorf("KB source cutover checkpoint is invalid")
	}
	parts := strings.Split(strings.TrimPrefix(value, kbSourceCutoverCheckpointPrefix), "|")
	if len(parts) != 2 {
		return kbSourceCutoverCheckpoint{}, fmt.Errorf("KB source cutover checkpoint is invalid")
	}
	checkpoint := kbSourceCutoverCheckpoint{
		SourceContentVersionID: strings.TrimSpace(parts[0]),
		UADashboardVersionID:   strings.TrimSpace(parts[1]),
	}
	if !validKBSourceCutoverVersionID(checkpoint.SourceContentVersionID) ||
		(checkpoint.UADashboardVersionID != "" && !validKBSourceCutoverVersionID(checkpoint.UADashboardVersionID)) {
		return kbSourceCutoverCheckpoint{}, fmt.Errorf("KB source cutover checkpoint is invalid")
	}
	return checkpoint, nil
}

func validKBSourceCutoverVersionID(value string) bool {
	value = strings.TrimSpace(value)
	return strings.HasPrefix(value, "ctv_") && len(value) <= 64 && !strings.ContainsAny(value, "|\x00")
}
