package controlplane

import (
	"context"
	"database/sql"

	"github.com/nexuscrm/analytics"
	"github.com/nexuscrm/auth"
	"github.com/nexuscrm/automation/autonumber"
	"github.com/pingcap-inc/nexuscrm-controlplane/packs"
	"github.com/nexuscrm/db"
	"github.com/nexuscrm/kernel/pkg/ports"
	"github.com/nexuscrm/metadata"
	"github.com/nexuscrm/permissions"
	"github.com/nexuscrm/records"
)

// ServiceGraph is the narrow consumer interface the control-plane Runner reads
// from the application service graph. It is declared HERE (by the consumer) so
// the control-plane module does not depend on the backend composition root's
// application service package: that package satisfies this interface
// structurally, and the backend composition root (pkg/serverruntime) constructs
// the concrete graph and injects it.
//
// Every return type is a workspace sibling already reachable by this module
// (metadata.*, analytics.*, permissions.*, auth.*, autonumber.*), so the
// interface adds no new dependency edge.
type ServiceGraph interface {
	Metadata() *metadata.MetadataService
	Schema() *metadata.SchemaManager
	Permissions() *permissions.PermissionService
	FormulaView() *analytics.FormulaViewService
	AutoNumberMetadata() *autonumber.MetadataSource
	Auth() *auth.AuthService
	ConnectorInbound() ConnectorInboundLifecycle
	System() packs.SystemAdmin

	// Record-setup surface. Integration/crm-tagged tests build fixtures and run
	// assertions through the concrete record/query API of the application graph;
	// these accessors expose it so those tests reach a real, DB-backed graph via
	// this public seam (BuildServiceGraph) instead of importing the backend
	// composition root's application/services package. Every return type is a
	// workspace sibling already reachable by this module (records.*,
	// ports.QueryService) or the standard library (*sql.DB), so they add no new
	// dependency edge.
	Persistence() *records.PersistenceService
	QuerySvc() ports.QueryService
	DB() *sql.DB

	RefreshMetadataCache(ctx context.Context) error
	ReconcileChangedConnectorInboundWorkers(ctx context.Context) error
}

// ConnectorInboundLifecycle mirrors the connector inbound worker lifecycle the
// Runner needs to observe. The Runner only checks presence (nil vs non-nil)
// before delegating to ReconcileChangedConnectorInboundWorkers, but the full
// method set is declared so the concrete supervisor satisfies it structurally.
type ConnectorInboundLifecycle interface {
	Start() error
	Reconcile(context.Context) error
	ReconcileChanged(context.Context) error
	Stop() error
}

// RunnerInfra carries the infrastructure handles the Runner threads into pack
// ApplyDeps. These are the only fields of the former services.InfrastructureDeps
// the control-plane path reads, all typed as kernel port interfaces.
type RunnerInfra struct {
	TxManager    ports.TransactionManager
	MetadataRepo ports.MetadataRepository
	SessionRepo  ports.SessionRepository
}

// BuildServiceGraph is the composition seam. The backend composition root
// (pkg/serverruntime) registers a builder that constructs the infrastructure
// dependencies and the application ServiceManager (in headless / NoOpEventBus
// mode) and returns them as a ServiceGraph + RunnerInfra. It is a package-level
// variable rather than a direct call so this module never imports the
// application service package. NewRunner fails fast if it is unset.
var BuildServiceGraph func(db *database.TiDBConnection) (ServiceGraph, RunnerInfra, error)
