package controlplane

import (
	"context"
	"database/sql"
	"fmt"
	"sort"
	"strings"

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

type applyAllSourceRevisionAdvanceAttributionRetryPeer struct {
	row    installedPackRow
	target *packs.SourceBackedPack
}

// applyAllSourceRevisionAdvanceAttributionRetryAuthority retains the exact
// unminted prepared-attempt identity. Every use revalidates that identity and
// derives retry peers from its admitted proof instead of trusting a name list.
type applyAllSourceRevisionAdvanceAttributionRetryAuthority struct {
	prepared         *applyAllSourceRevisionAdvanceAttemptIdentity
	plannedDesired   *installPackPreflightPackContext
	runtimeEffective *installPackPreflightPackContext
}

// buildApplyAllSourceRevisionAdvanceAttributionPreflightOverrides derives the
// three attribution roles from one exact prepared attempt: all desired targets,
// live runtime-effective current targets, and proof-bound retry peers. It is
// consumed only by the exact live-preflight capability.
func buildApplyAllSourceRevisionAdvanceAttributionPreflightOverrides(
	prepared *applyAllSourceRevisionAdvanceAttemptIdentity,
) (*installPackPreflightOverrides, error) {
	state, err := requireApplyAllSourceRevisionAdvancePreparedAttributionState(prepared)
	if err != nil {
		return nil, err
	}
	planned, runtimeEffective := applyAllSourceRevisionAdvanceAttributionTargets(state.proof)
	plannedContext, err := newInstallPackPreflightPackContext(planned)
	if err != nil {
		return nil, fmt.Errorf("build exact desired-pack context: %w", err)
	}
	runtimeContext, err := newInstallPackPreflightPackContext(runtimeEffective)
	if err != nil {
		return nil, fmt.Errorf("build exact runtime-effective context: %w", err)
	}
	return &installPackPreflightOverrides{
		plannedDesiredPacks:   plannedContext,
		runtimeEffectivePacks: runtimeContext,
		sourceRevisionAdvanceRetryPeers: &applyAllSourceRevisionAdvanceAttributionRetryAuthority{
			prepared: prepared, plannedDesired: plannedContext, runtimeEffective: runtimeContext,
		},
	}, nil
}

func applyAllSourceRevisionAdvanceAttributionTargets(
	proof *applyAllSourceRevisionAdvanceExecutionProof,
) (map[string]*packs.SourceBackedPack, map[string]*packs.SourceBackedPack) {
	planned := make(map[string]*packs.SourceBackedPack, len(proof.entries))
	runtimeEffective := make(map[string]*packs.SourceBackedPack, len(proof.entries))
	for _, entry := range proof.entries {
		planned[entry.name] = entry.installedCompatibility
		if entry.current.row.Status == installedPackStatusActive && entry.current.row.IsDeleted == 0 {
			runtimeEffective[entry.name] = entry.currentTarget
		}
	}
	return planned, runtimeEffective
}

type applyAllSourceRevisionAdvancePreparedAttributionState struct {
	proof    *applyAllSourceRevisionAdvanceExecutionProof
	selected applyAllSourceRevisionAdvanceExecutionProofEntry
}

func requireApplyAllSourceRevisionAdvancePreparedAttributionState(
	prepared *applyAllSourceRevisionAdvanceAttemptIdentity,
) (applyAllSourceRevisionAdvancePreparedAttributionState, error) {
	if err := validateApplyAllSourceRevisionAdvanceAttemptIdentity(prepared, false); err != nil {
		return applyAllSourceRevisionAdvancePreparedAttributionState{}, fmt.Errorf(
			"validate prepared source-revision attribution authority: %w", err,
		)
	}
	proof := &prepared.admission.identity.proof
	selected := proof.entries[prepared.selectedProofIndex]
	if selected.current.pending == nil ||
		(selected.current.pending.Kind != ApplyAllSourceRevisionAdvancePendingAdvance &&
			selected.current.pending.Kind != ApplyAllSourceRevisionAdvancePendingRetry) {
		return applyAllSourceRevisionAdvancePreparedAttributionState{}, fmt.Errorf(
			"selected source-revision attribution target is not an advance or retry",
		)
	}
	return applyAllSourceRevisionAdvancePreparedAttributionState{
		proof: proof, selected: selected,
	}, nil
}

func bindApplyAllSourceRevisionAdvanceAttributionRetryPeers(
	overrides *installPackPreflightOverrides,
	requested *packs.SourceBackedPack,
	db *sql.DB,
	registrations packs.ComponentKindRegistrationSet,
) (map[string]applyAllSourceRevisionAdvanceAttributionRetryPeer, error) {
	if overrides == nil || overrides.sourceRevisionAdvanceRetryPeers == nil {
		return nil, nil
	}
	authority := overrides.sourceRevisionAdvanceRetryPeers
	state, err := requireApplyAllSourceRevisionAdvancePreparedAttributionState(authority.prepared)
	if err != nil {
		return nil, err
	}
	if requested == nil || requested != state.selected.installedCompatibility {
		return nil, fmt.Errorf("requested pack is not the exact prepared source-revision target")
	}
	if db == nil || db != state.proof.provenance.activeRuntimeDatabase {
		return nil, fmt.Errorf("attribution database is not the exact prepared runtime database")
	}
	if state.proof.executionRuntime == nil ||
		!state.proof.executionRuntime.componentKindRegistrationSet.SameSnapshot(registrations) {
		return nil, fmt.Errorf("attribution component registrations changed from the prepared runtime")
	}
	planned, runtimeEffective := applyAllSourceRevisionAdvanceAttributionTargets(state.proof)
	if overrides.plannedDesiredPacks != authority.plannedDesired ||
		!sameApplyAllSourceRevisionAdvanceAttributionPackContext(authority.plannedDesired, planned) {
		return nil, fmt.Errorf("prepared source-revision desired-pack context changed")
	}
	if overrides.runtimeEffectivePacks != authority.runtimeEffective ||
		!sameApplyAllSourceRevisionAdvanceAttributionPackContext(authority.runtimeEffective, runtimeEffective) {
		return nil, fmt.Errorf("prepared source-revision runtime-effective context changed")
	}
	retryPeers := make(map[string]applyAllSourceRevisionAdvanceAttributionRetryPeer)
	for index, entry := range state.proof.entries {
		if index == authority.prepared.selectedProofIndex {
			continue
		}
		if entry.current.pending == nil || entry.current.pending.Kind != ApplyAllSourceRevisionAdvancePendingRetry {
			continue
		}
		name := strings.ToLower(strings.TrimSpace(entry.name))
		if name == "" {
			return nil, fmt.Errorf("prepared source-revision retry peer has an empty name")
		}
		retryPeers[name] = applyAllSourceRevisionAdvanceAttributionRetryPeer{
			row: entry.current.row, target: entry.installedCompatibility,
		}
	}
	return retryPeers, nil
}

func sameApplyAllSourceRevisionAdvanceAttributionPackContext(
	context *installPackPreflightPackContext,
	want map[string]*packs.SourceBackedPack,
) bool {
	if context == nil || len(context.byName) != len(want) {
		return false
	}
	for name, target := range want {
		if context.byName[name] != target {
			return false
		}
	}
	return true
}

func validateApplyAllSourceRevisionAdvanceAttributionRetryPeerRows(
	ctx context.Context,
	db *sql.DB,
	retryPeers map[string]applyAllSourceRevisionAdvanceAttributionRetryPeer,
) error {
	names := make([]string, 0, len(retryPeers))
	for name := range retryPeers {
		names = append(names, name)
	}
	sort.Strings(names)
	for _, name := range names {
		peer := retryPeers[name]
		live, ok, err := getInstalledPackRowByNameForSourceRevisionAdvance(ctx, db, name)
		if err != nil {
			return fmt.Errorf("proof-bound retry peer %s exact row reread: %w", name, err)
		}
		if !ok || live != peer.row {
			return fmt.Errorf("proof-bound retry peer %s changed after execution admission", name)
		}
	}
	return nil
}
