package controlplane

import (
	"fmt"
	"strings"

	"github.com/pingcap-inc/nexuscrm-controlplane/packs"
)

// validateApplyAllSourceRevisionAdvanceFrozenCurrentTargetFacts binds every
// reconstructed current target to the durable facts in its frozen installed
// row. It returns no capability and performs no reads or writes.
func validateApplyAllSourceRevisionAdvanceFrozenCurrentTargetFacts(
	precondition applyAllSourceRevisionAdvancePreconditionProof,
) error {
	if precondition.snapshot.entries == nil || precondition.current.plan == nil || precondition.current.targets == nil {
		return applyAllSourceRevisionAdvancePlanError(
			ApplyAllSourceRevisionAdvancePlanState, -1, "", fmt.Errorf("current precondition proof was not minted"),
		)
	}
	if err := validateApplyAllSourceRevisionAdvanceCurrentPayloads(precondition.snapshot, precondition.current); err != nil {
		return err
	}

	seen := make(map[string]struct{}, len(precondition.snapshot.entries))
	for _, entry := range precondition.snapshot.entries {
		advance := entry.advance
		name := strings.ToLower(strings.TrimSpace(advance.Name))
		if name == "" {
			return applyAllSourceRevisionAdvanceCurrentTargetFactsError(advance, fmt.Errorf("canonical pack name is empty"))
		}
		if _, duplicate := seen[name]; duplicate {
			return applyAllSourceRevisionAdvanceCurrentTargetFactsError(advance, fmt.Errorf("frozen proof duplicates canonical pack name %q", name))
		}
		seen[name] = struct{}{}
		if err := validateApplyAllSourceRevisionAdvanceFrozenCurrentTargetEntry(
			entry, precondition.current.targets[name],
		); err != nil {
			return applyAllSourceRevisionAdvanceCurrentTargetFactsError(advance, err)
		}
	}
	return nil
}

func validateApplyAllSourceRevisionAdvanceFrozenCurrentTargetEntry(
	entry applyAllSourceRevisionAdvanceCurrentSnapshotEntry,
	target *packs.SourceBackedPack,
) error {
	advance := entry.advance
	row := entry.row
	if row.Name != advance.Name {
		return fmt.Errorf("frozen installed row name does not match its advance")
	}
	if target == nil || strings.TrimSpace(row.Category) != string(target.Category()) {
		return fmt.Errorf("frozen installed row category does not match its current target")
	}
	if !sourceIdentityMatches(row, packs.PackHashMetadataForPack(target)) {
		return fmt.Errorf("frozen installed row source identity does not match its current target")
	}
	pending, err := classifyApplyAllSourceRevisionAdvance(row, advance.SourceRevisionAdvanceAuthorization)
	if err != nil {
		return fmt.Errorf("reclassify frozen installed row: %w", err)
	}
	if !equalApplyAllSourceRevisionAdvancePending(pending, entry.pending) {
		return fmt.Errorf("frozen pending classification does not match installed row")
	}

	switch row.Status {
	case installedPackStatusActive:
		if row.IsDeleted != 0 {
			return fmt.Errorf("frozen active installed row is deleted")
		}
		appliedHash := strings.TrimSpace(row.AppliedPayloadHash.String)
		if !row.AppliedPayloadHash.Valid || appliedHash == "" {
			return fmt.Errorf("frozen active installed row AppliedPayloadHash is empty")
		}
		format, err := packs.ValidateStoredPackPayloadHash(target, appliedHash)
		if err != nil {
			return fmt.Errorf("frozen active installed row AppliedPayloadHash does not match its current target: %w", err)
		}
		if format == packs.PayloadHashFormatV1 {
			if err := verifyInstalledPackHashMetadata(row, target); err != nil {
				return fmt.Errorf("frozen active installed row hash metadata does not match its current target: %w", err)
			}
		}
	case installedPackStatusFailed, installedPackStatusInstalling:
		desiredHash := strings.TrimSpace(row.DesiredPayloadHash.String)
		if !row.DesiredPayloadHash.Valid || desiredHash == "" {
			return fmt.Errorf("frozen retryable installed row DesiredPayloadHash is empty")
		}
		currentHash, err := packs.PackPayloadHash(target)
		if err != nil {
			return fmt.Errorf("hash frozen retryable current target: %w", err)
		}
		if desiredHash != currentHash {
			return fmt.Errorf("frozen retryable installed row DesiredPayloadHash does not match its current target")
		}
		if err := verifyInstalledPackHashMetadata(row, target); err != nil {
			return fmt.Errorf("frozen retryable installed row hash metadata does not match its current target: %w", err)
		}
	}
	if err := verifyInstalledPackHostRequirementsState(row, target); err != nil {
		return fmt.Errorf("frozen installed row host requirements do not match its current target: %w", err)
	}
	return nil
}

func equalApplyAllSourceRevisionAdvancePending(
	left *PendingApplyAllSourceRevisionAdvance,
	right *PendingApplyAllSourceRevisionAdvance,
) bool {
	if left == nil || right == nil {
		return left == nil && right == nil
	}
	return *left == *right
}

func applyAllSourceRevisionAdvanceCurrentTargetFactsError(
	advance normalizedApplyAllSourceRevisionAdvance,
	err error,
) error {
	return applyAllSourceRevisionAdvancePlanError(
		ApplyAllSourceRevisionAdvancePlanState, advance.index, advance.Name,
		fmt.Errorf("validate frozen current target facts: %w", err),
	)
}
