package controlplane

import (
	"context"

	"github.com/nexuscrm/backend/internal/application/services"
	"github.com/nexuscrm/backend/internal/controlplane/packs"
	"github.com/nexuscrm/backend/internal/features/events"
	"github.com/nexuscrm/backend/internal/infrastructure/database"
)

// Runner is a headless control-plane runtime. It builds the application
// service graph (MetadataService, PermissionService, etc.) WITHOUT starting
// the HTTP server, background workers, or session cleanup. A NoOpEventBus
// is injected so listener subscriptions are inert during pack apply.
type Runner struct {
	DB        *database.TiDBConnection
	InfraDeps services.InfrastructureDeps
	SvcMgr    *services.ServiceManager
}

// NewRunner creates a headless control-plane runtime.
func NewRunner(db *database.TiDBConnection) (*Runner, error) {
	infraDeps := BuildInfrastructureDeps(db)

	// Headless mode: inject NoOpEventBus so listeners are inert.
	infraDeps.EventBus = &events.NoOpEventBus{}
	// No-op metrics callbacks (no Prometheus in headless mode).
	infraDeps.OnEventDropped = func(string) {}
	infraDeps.OnQueueUtilizationChange = func(float64) {}

	svcMgr, err := services.NewServiceManager(infraDeps)
	if err != nil {
		return nil, err
	}

	return &Runner{
		DB:        db,
		InfraDeps: infraDeps,
		SvcMgr:    svcMgr,
	}, nil
}

// RefreshCache refreshes the metadata cache from the database.
func (r *Runner) RefreshCache(ctx context.Context) error {
	return r.SvcMgr.RefreshMetadataCache(ctx)
}

// PackDeps adapts the Runner's service graph into pack ApplyDeps.
func (r *Runner) PackDeps() packs.ApplyDeps {
	return packs.ApplyDeps{
		DB:           r.DB.DB(),
		DBConn:       r.DB,
		TxManager:    r.InfraDeps.TxManager,
		Metadata:     r.SvcMgr.Metadata,
		Schema:       r.SvcMgr.Schema,
		Permissions:  r.SvcMgr.Permissions,
		System:       r.SvcMgr.System,
		FormulaView:  r.SvcMgr.FormulaViewSvc,
		MetadataRepo: r.InfraDeps.MetadataRepo,
	}
}
