package controlplane

import (
	"context"
	"database/sql"

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

// ReconcileFlowOrphans repairs FlowDefinition rows whose ActiveVersionId fails
// any of the four integrity properties checked by VerifyFlowDataIntegrity:
//
//  1. Dangling ActiveVersionId: the referenced Flow row no longer exists.
//  2. Cross-definition pointer: the Flow exists but belongs to a different
//     FlowDefinition (fv.DefinitionId != fd.Id).
//  3. Soft-deleted active version: the Flow is marked IsDeleted = TRUE.
//  4. Non-Active status: the Flow's Status is Draft, Obsolete, or other
//     non-Active value.
//  5. Deleted+active collision: IsDeleted = TRUE on the FlowDefinition itself
//     but ActiveVersionId is still non-null.
//
// For every affected row, ActiveVersionId is set to NULL.  A single atomic
// UPDATE re-evaluates the broken predicate at write time (DB row lock),
// so a concurrent Tooling API writer that repairs a definition between the
// audit SELECT and this UPDATE will cause the row to no longer match the
// predicate — the UPDATE skips it rather than silently deactivating it.
//
// The reconcile predicate mirrors the verify predicate exactly so that every
// state flagged by VerifyFlowDataIntegrity is also auto-healed by this function.
//
// The operation is idempotent: running it a second time against an already
// repaired database returns touched=0 without modifying any rows.
func ReconcileFlowOrphans(ctx context.Context, db *database.TiDBConnection) (touched int, err error) {
	return packs.ReconcileFlowOrphans(ctx, db)
}

// reconcileFlowOrphans is the internal implementation operating on *sql.DB so
// it can be called from tests using sqlmock without a TiDBConnection wrapper.
func reconcileFlowOrphans(ctx context.Context, rawDB *sql.DB) (int, error) {
	return packs.ReconcileFlowOrphansRaw(ctx, rawDB)
}
