package controlplane

import (
	"context"
	"database/sql"
	"errors"
	"fmt"
	"slices"
	"strings"
	"sync/atomic"
)

type applyAllSourceRevisionAdvanceAmbiguousActivationClaim struct {
	claimed atomic.Bool
}

// applyAllSourceRevisionAdvanceAmbiguousActivationError is the only carrier
// allowed to classify an unknown activation commit. It binds the commit error
// to the exact finalization authority that issued the transaction and exposes
// a one-shot reconciliation claim to the still-lock-held orchestrator.
type applyAllSourceRevisionAdvanceAmbiguousActivationError struct {
	identity *applyAllSourceRevisionAdvanceAmbiguousActivationIdentity
	witness  applyAllSourceRevisionAdvanceAmbiguousActivationProvenance
}

type applyAllSourceRevisionAdvanceAmbiguousActivationIdentity struct {
	authority  applyAllSourceRevisionAdvanceFinalizationAuthority
	commitErr  *applyAllSourceRevisionAdvanceExactIncarnationCommitError
	claim      *applyAllSourceRevisionAdvanceAmbiguousActivationClaim
	success    applyAllSourceRevisionAdvanceSuccess
	provenance *applyAllSourceRevisionAdvanceAmbiguousActivationProvenance
	minted     bool
}

type applyAllSourceRevisionAdvanceAmbiguousActivationProvenance struct {
	authorityIdentity *applyAllSourceRevisionAdvanceFinalizationAuthorityIdentity
	commitErr         *applyAllSourceRevisionAdvanceExactIncarnationCommitError
	claim             *applyAllSourceRevisionAdvanceAmbiguousActivationClaim
	success           applyAllSourceRevisionAdvanceSuccess
}

func (e *applyAllSourceRevisionAdvanceAmbiguousActivationError) Error() string {
	if e == nil || e.identity == nil || e.identity.commitErr == nil {
		return "source revision activation commit outcome is unknown"
	}
	return "source revision activation commit outcome is unknown: " + e.identity.commitErr.Error()
}

func (e *applyAllSourceRevisionAdvanceAmbiguousActivationError) Unwrap() error {
	if e == nil || e.identity == nil {
		return nil
	}
	return e.identity.commitErr
}

type applyAllSourceRevisionAdvanceActivationCommitOutcome string

const (
	applyAllSourceRevisionAdvanceActivationCommitted    applyAllSourceRevisionAdvanceActivationCommitOutcome = "committed"
	applyAllSourceRevisionAdvanceActivationNotCommitted applyAllSourceRevisionAdvanceActivationCommitOutcome = "not_committed"
)

type applyAllSourceRevisionAdvanceActivationReconciliation struct {
	outcome applyAllSourceRevisionAdvanceActivationCommitOutcome
	success applyAllSourceRevisionAdvanceSuccess
}

type applyAllSourceRevisionAdvanceActivationReconciliationOperations struct {
	readInstalledRow func(
		context.Context, *sql.DB, string,
	) (installedPackRow, bool, error)
	verifySourceBackedGeneration func(
		context.Context, *sql.DB, appliedAppPack,
	) error
}

type applyAllSourceRevisionAdvanceAmbiguousActivationState struct {
	attempt applyAllSourceRevisionAdvanceAttemptState
	claim   *applyAllSourceRevisionAdvanceAmbiguousActivationClaim
}

func mintApplyAllSourceRevisionAdvanceAmbiguousActivationError(
	authority applyAllSourceRevisionAdvanceFinalizationAuthority,
	commitErr *applyAllSourceRevisionAdvanceExactIncarnationCommitError,
	success applyAllSourceRevisionAdvanceSuccess,
) (*applyAllSourceRevisionAdvanceAmbiguousActivationError, error) {
	if _, err := requireApplyAllSourceRevisionAdvanceFinalizationAuthority(authority); err != nil {
		return nil, err
	}
	if commitErr == nil {
		return nil, fmt.Errorf("exact activation commit error is required")
	}
	claim := &applyAllSourceRevisionAdvanceAmbiguousActivationClaim{}
	identity := &applyAllSourceRevisionAdvanceAmbiguousActivationIdentity{
		authority: authority,
		commitErr: commitErr,
		claim:     claim,
		success:   cloneApplyAllSourceRevisionAdvanceSuccess(success),
		minted:    true,
	}
	identity.provenance = &applyAllSourceRevisionAdvanceAmbiguousActivationProvenance{
		authorityIdentity: authority.identity,
		commitErr:         commitErr,
		claim:             claim,
		success:           cloneApplyAllSourceRevisionAdvanceSuccess(success),
	}
	witness := *identity.provenance
	witness.success = cloneApplyAllSourceRevisionAdvanceSuccess(success)
	ambiguous := &applyAllSourceRevisionAdvanceAmbiguousActivationError{
		identity: identity,
		witness:  witness,
	}
	if _, err := requireApplyAllSourceRevisionAdvanceAmbiguousActivation(ambiguous); err != nil {
		return nil, err
	}
	return ambiguous, nil
}

func requireApplyAllSourceRevisionAdvanceAmbiguousActivation(
	ambiguous *applyAllSourceRevisionAdvanceAmbiguousActivationError,
) (applyAllSourceRevisionAdvanceAmbiguousActivationState, error) {
	if ambiguous == nil || ambiguous.identity == nil || !ambiguous.identity.minted ||
		ambiguous.identity.provenance == nil {
		return applyAllSourceRevisionAdvanceAmbiguousActivationState{}, fmt.Errorf(
			"ambiguous activation authority was not minted by exact finalization",
		)
	}
	identity := ambiguous.identity
	provenance := identity.provenance
	if identity.authority.identity == nil ||
		identity.authority.identity != provenance.authorityIdentity ||
		identity.authority.identity != ambiguous.witness.authorityIdentity {
		return applyAllSourceRevisionAdvanceAmbiguousActivationState{}, fmt.Errorf(
			"ambiguous activation changed finalization authority",
		)
	}
	if identity.commitErr == nil || identity.commitErr != provenance.commitErr ||
		identity.commitErr != ambiguous.witness.commitErr {
		return applyAllSourceRevisionAdvanceAmbiguousActivationState{}, fmt.Errorf(
			"ambiguous activation changed its exact commit error",
		)
	}
	if identity.claim == nil || identity.claim != provenance.claim ||
		identity.claim != ambiguous.witness.claim {
		return applyAllSourceRevisionAdvanceAmbiguousActivationState{}, fmt.Errorf(
			"ambiguous activation changed its reconciliation claim",
		)
	}
	if !slices.Equal(
		identity.success.connectedAppChangedIDs,
		provenance.success.connectedAppChangedIDs,
	) || !slices.Equal(
		identity.success.connectedAppChangedIDs,
		ambiguous.witness.success.connectedAppChangedIDs,
	) {
		return applyAllSourceRevisionAdvanceAmbiguousActivationState{}, fmt.Errorf(
			"ambiguous activation changed its transactional success result",
		)
	}
	authorityState, err := requireApplyAllSourceRevisionAdvanceFinalizationAuthority(
		identity.authority,
	)
	if err != nil {
		return applyAllSourceRevisionAdvanceAmbiguousActivationState{}, fmt.Errorf(
			"validate ambiguous activation finalization authority: %w", err,
		)
	}
	attemptState, err := requireApplyAllSourceRevisionAdvanceAttempt(
		authorityState.attempt, "reconcile activation",
	)
	if err != nil {
		return applyAllSourceRevisionAdvanceAmbiguousActivationState{}, err
	}
	return applyAllSourceRevisionAdvanceAmbiguousActivationState{
		attempt: attemptState,
		claim:   identity.claim,
	}, nil
}

// reconcileApplyAllSourceRevisionAdvanceAmbiguousActivation must run before
// the caller releases the ApplyAll advisory lock. The production wrapper first
// validates the live lock scope; this inner classifier then rereads the durable
// whole tuple and compares it fail-closed in one uninterrupted call. No inverse
// effect is applied here.
func reconcileApplyAllSourceRevisionAdvanceAmbiguousActivation(
	ctx context.Context,
	activationErr error,
) (applyAllSourceRevisionAdvanceActivationReconciliation, error) {
	return reconcileApplyAllSourceRevisionAdvanceAmbiguousActivationWith(
		ctx,
		activationErr,
		applyAllSourceRevisionAdvanceActivationReconciliationOperations{
			readInstalledRow:             getInstalledPackRowByNameForSourceRevisionAdvance,
			verifySourceBackedGeneration: verifyPublishedSourceBackedPackGeneration,
		},
	)
}

func reconcileApplyAllSourceRevisionAdvanceAmbiguousActivationUnderApplyLock(
	ctx context.Context,
	applyLock controlPlaneApplyLockScope,
	database *sql.DB,
	activationErr error,
) (applyAllSourceRevisionAdvanceActivationReconciliation, error) {
	if database == nil {
		return applyAllSourceRevisionAdvanceActivationReconciliation{}, fmt.Errorf(
			"reconcile ambiguous activation under ApplyAll lock: database is unavailable",
		)
	}
	if err := requireControlPlaneApplyLockScope(applyLock); err != nil {
		return applyAllSourceRevisionAdvanceActivationReconciliation{}, fmt.Errorf(
			"reconcile ambiguous activation under ApplyAll lock: %w", err,
		)
	}
	var ambiguous *applyAllSourceRevisionAdvanceAmbiguousActivationError
	if !errors.As(activationErr, &ambiguous) {
		return applyAllSourceRevisionAdvanceActivationReconciliation{}, fmt.Errorf(
			"reconcile ambiguous activation under ApplyAll lock: exact ambiguous activation error is required",
		)
	}
	state, err := requireApplyAllSourceRevisionAdvanceAmbiguousActivation(ambiguous)
	if err != nil {
		return applyAllSourceRevisionAdvanceActivationReconciliation{}, err
	}
	if state.attempt.database != database {
		return applyAllSourceRevisionAdvanceActivationReconciliation{}, fmt.Errorf(
			"reconcile ambiguous activation under ApplyAll lock: attempt belongs to a different runner database",
		)
	}
	return reconcileApplyAllSourceRevisionAdvanceAmbiguousActivation(
		ctx, activationErr,
	)
}

func reconcileApplyAllSourceRevisionAdvanceAmbiguousActivationWith(
	ctx context.Context,
	activationErr error,
	operations applyAllSourceRevisionAdvanceActivationReconciliationOperations,
) (applyAllSourceRevisionAdvanceActivationReconciliation, error) {
	var ambiguous *applyAllSourceRevisionAdvanceAmbiguousActivationError
	if !errors.As(activationErr, &ambiguous) {
		return applyAllSourceRevisionAdvanceActivationReconciliation{}, fmt.Errorf(
			"exact ambiguous activation error is required",
		)
	}
	state, err := requireApplyAllSourceRevisionAdvanceAmbiguousActivation(ambiguous)
	if err != nil {
		return applyAllSourceRevisionAdvanceActivationReconciliation{}, err
	}
	if operations.readInstalledRow == nil {
		return applyAllSourceRevisionAdvanceActivationReconciliation{}, fmt.Errorf(
			"ambiguous activation installed-row reader is required",
		)
	}
	if !state.claim.claimed.CompareAndSwap(false, true) {
		return applyAllSourceRevisionAdvanceActivationReconciliation{},
			applyAllSourceRevisionAdvanceAttemptError(
				"reconcile activation", state.attempt.advance,
				fmt.Errorf("ambiguous activation was already reconciled"),
			)
	}

	proof := state.attempt.identity.admission.identity.proof
	selectedIndex := state.attempt.identity.selectedProofIndex
	selectedOutcome := applyAllSourceRevisionAdvanceActivationCommitOutcome("")
	for index, entry := range proof.entries {
		live, ok, err := operations.readInstalledRow(
			ctx, state.attempt.database, entry.current.advance.Name,
		)
		if err != nil {
			return applyAllSourceRevisionAdvanceActivationReconciliation{},
				applyAllSourceRevisionAdvanceAttemptError(
					"reconcile activation", state.attempt.advance,
					fmt.Errorf("reread admitted tuple row %s: %w", entry.current.advance.Name, err),
				)
		}
		if !ok {
			return applyAllSourceRevisionAdvanceActivationReconciliation{},
				applyAllSourceRevisionAdvanceAttemptError(
					"reconcile activation", state.attempt.advance,
					fmt.Errorf("admitted tuple row %s is missing", entry.current.advance.Name),
				)
		}
		if index != selectedIndex {
			if live != entry.current.row {
				return applyAllSourceRevisionAdvanceActivationReconciliation{},
					applyAllSourceRevisionAdvanceAttemptError(
						"reconcile activation", state.attempt.advance,
						fmt.Errorf("nonselected admitted tuple row %s changed", entry.current.advance.Name),
					)
			}
			continue
		}

		installing := state.attempt.identity.installingRow
		active := installing
		active.Status = installedPackStatusActive
		active.AppliedPayloadHash = sql.NullString{
			Valid:  true,
			String: state.attempt.facts.PayloadHash,
		}
		switch live {
		case installing:
			selectedOutcome = applyAllSourceRevisionAdvanceActivationNotCommitted
		case active:
			selectedOutcome = applyAllSourceRevisionAdvanceActivationCommitted
		default:
			return applyAllSourceRevisionAdvanceActivationReconciliation{},
				applyAllSourceRevisionAdvanceAttemptError(
					"reconcile activation", state.attempt.advance,
					fmt.Errorf(
						"selected row %s matches neither exact installing nor exact active incarnation",
						strings.TrimSpace(entry.current.advance.Name),
					),
				)
		}
	}
	if selectedOutcome == "" {
		return applyAllSourceRevisionAdvanceActivationReconciliation{},
			applyAllSourceRevisionAdvanceAttemptError(
				"reconcile activation", state.attempt.advance,
				fmt.Errorf("selected admitted tuple row was not reread"),
			)
	}
	reconciliation := applyAllSourceRevisionAdvanceActivationReconciliation{
		outcome: selectedOutcome,
	}
	if selectedOutcome == applyAllSourceRevisionAdvanceActivationCommitted {
		if operations.verifySourceBackedGeneration == nil {
			return applyAllSourceRevisionAdvanceActivationReconciliation{},
				applyAllSourceRevisionAdvanceAttemptError(
					"reconcile activation", state.attempt.advance,
					fmt.Errorf("source-backed generation reconciliation verifier is required"),
				)
		}
		if err := operations.verifySourceBackedGeneration(
			ctx,
			state.attempt.database,
			appliedAppPack{
				pack:        state.attempt.target,
				payloadHash: state.attempt.facts.PayloadHash,
			},
		); err != nil {
			return applyAllSourceRevisionAdvanceActivationReconciliation{},
				applyAllSourceRevisionAdvanceAttemptError(
					"reconcile activation", state.attempt.advance,
					fmt.Errorf("reread immutable generation activation: %w", err),
				)
		}
		reconciliation.success = cloneApplyAllSourceRevisionAdvanceSuccess(
			ambiguous.identity.success,
		)
	}
	return reconciliation, nil
}
