package packs

import (
	"context"
	"database/sql"

	connector "github.com/pingcap-inc/nexuscrm-contract/pkg/connector"
)

// CONTROL-PLANE SEAM — control-plane imports bootstrap = ZERO (W5/S7).
//
// The relocated connector field-mapping write/init/verify functions
// (connector_field_mapping_pack.go in this package) consult the SHARED
// connector-mapping READ surface through these package-level function seams
// instead of importing internal/bootstrap at the call site. The reader
// functions are shared with the automation feature (via the contract
// runtimeports.ConnectorFieldMappingReader port) and therefore stay in their
// owning composition host, internal/bootstrap; only the write side relocates
// to controlplane.
//
// These seams are db-passing (the canonical bootstrap reader free functions
// take the caller-supplied *sql.DB) so behavior is byte-for-byte identical to
// the prior direct bootstrap.ResolveFieldMapping call: the read always runs on
// the same DB the apply/verify pipeline supplied, in every entry point
// (cmd/setup apply, server runtime, integration tests). The contract
// runtimeports.ConnectorFieldMappingReader port binds a *sql.DB at
// construction and so cannot carry the per-call DB these CP apply/verify sites
// pass; a db-passing function seam is the behavior-preserving route. The packs
// package no longer references internal/bootstrap; the concrete readers are
// injected at the composition roots (pkg/serverruntime via WireControlplaneSeams,
// internal/setupcmd, packs test wiring) via the setters below — never defaulted
// here.
//
// Mandatory injection: the resolve seam is on the live connector apply/verify
// path and MUST be wired before that path runs; getFieldMappings is consulted
// only by the relocated tests. Unwired seams are nil.
var (
	resolveFieldMapping              func(context.Context, *sql.DB, ResolveQuery) ([]connector.ConnectorFieldMappingInput, error)
	resolvePackConnectorFieldMapping func(context.Context, *sql.DB, ResolveQuery) ([]connector.ConnectorFieldMappingInput, error)
	// getFieldMappings is the db-passing route to the shared bootstrap legacy
	// field-mapping reader, used by the relocated connector-mapping tests in
	// this package so the test does not import internal/bootstrap directly. Like
	// the resolve seams it stays bootstrap-backed because the reader is shared
	// with the automation feature via the contract
	// runtimeports.ConnectorFieldMappingReader port; only the write side
	// relocated to controlplane.
	getFieldMappings func(*sql.DB, string, string, string) ([]connector.FieldMappingDef, error)
)

// SetResolveFieldMapping injects the shared connector field-mapping resolver.
// Intended for the composition roots / packs test wiring, which supply
// bootstrap.ResolveFieldMapping.
func SetResolveFieldMapping(f func(context.Context, *sql.DB, ResolveQuery) ([]connector.ConnectorFieldMappingInput, error)) {
	if f == nil {
		return
	}
	resolveFieldMapping = f
}

// SetResolvePackConnectorFieldMapping injects the shared pack-connector
// field-mapping resolver. Intended for the composition roots / packs test
// wiring, which supply bootstrap.ResolvePackConnectorFieldMapping.
func SetResolvePackConnectorFieldMapping(f func(context.Context, *sql.DB, ResolveQuery) ([]connector.ConnectorFieldMappingInput, error)) {
	if f == nil {
		return
	}
	resolvePackConnectorFieldMapping = f
}

// SetGetFieldMappings injects the shared legacy field-mapping reader. Intended
// for the composition roots / packs test wiring, which supply
// bootstrap.GetFieldMappings.
func SetGetFieldMappings(f func(*sql.DB, string, string, string) ([]connector.FieldMappingDef, error)) {
	if f == nil {
		return
	}
	getFieldMappings = f
}

// ResolveQuery is the connector mapping read filter (alias to the contract
// type the bootstrap reader already consumes), so relocated write-side code in
// this package can build queries without importing internal/bootstrap.
type ResolveQuery = connector.ResolveQuery

// ResolvePackConnectorFieldMapping is the exported db-passing route to the
// shared bootstrap reader of the same name, for control-plane callers outside
// this package (e.g. the connector-push legacy-mirror backfill) that previously
// called internal/bootstrap directly. It preserves the caller-supplied *sql.DB
// (the contract runtimeports port binds a DB at construction and so cannot
// carry the per-call DB these sites pass).
func ResolvePackConnectorFieldMapping(ctx context.Context, db *sql.DB, q ResolveQuery) ([]connector.ConnectorFieldMappingInput, error) {
	return resolvePackConnectorFieldMapping(ctx, db, q)
}

// compile-time guards that the seam vars keep the canonical reader signatures.
var (
	_ func(context.Context, *sql.DB, ResolveQuery) ([]connector.ConnectorFieldMappingInput, error) = resolveFieldMapping
	_ func(context.Context, *sql.DB, ResolveQuery) ([]connector.ConnectorFieldMappingInput, error) = resolvePackConnectorFieldMapping
	_ func(*sql.DB, string, string, string) ([]connector.FieldMappingDef, error)                    = getFieldMappings
)
