package controlplane

import (
	"database/sql"
	"testing"

	"github.com/nexuscrm/analytics"
	database "github.com/nexuscrm/db"
	"github.com/nexuscrm/metadata"
)

func TestFreezeApplyAllSourceRevisionAdvanceExecutionRuntimeRetainsAuthority(t *testing.T) {
	db := &sql.DB{}
	metadataA := &metadata.MetadataService{}
	graphA := newTestServiceGraph(testServiceGraphConfig{DB: db, Metadata: metadataA})
	runner := &Runner{
		DB: database.NewConnectionFromDB(db),
		SvcMgr: &runnerServiceGraph{
			ServiceGraph: graphA,
			options: RunnerOptions{
				ComponentKindRegistrationSet: runnerTestRegistrationSet(t),
			},
		},
	}
	wantServiceGraph := runner.SvcMgr
	runtime, err := freezeApplyAllSourceRevisionAdvanceExecutionRuntime(runner)
	if err != nil {
		t.Fatalf("freeze execution runtime: %v", err)
	}

	runner.SvcMgr.(*runnerServiceGraph).options = RunnerOptions{}
	runner.SvcMgr = newTestServiceGraph(testServiceGraphConfig{
		DB: db, Metadata: &metadata.MetadataService{},
	})
	if err := runtime.validate(); err != nil {
		t.Fatalf("validate retained execution runtime: %v", err)
	}
	registrations := runtime.componentKindRegistrationSet.Registrations()
	if runtime.serviceGraph != wantServiceGraph || runtime.applyDeps.Metadata != metadataA ||
		len(registrations) != 1 || registrations[0].Contract.Kind != "runner_test" {
		t.Fatalf("runtime authority changed after Runner mutation: %#v", runtime)
	}
	runtime.componentKindRegistrationSet = runnerTestRegistrationSet(t)
	if err := runtime.validate(); err == nil {
		t.Fatal("independently reconstructed registration set was accepted")
	}

	runtime.componentKindRegistrationSet = runtime.provenance.componentKindRegistrationSet
	runner.DB = database.NewConnectionFromDB(db)
	if err := runtime.validate(); err == nil {
		t.Fatal("replacement TiDB connection sharing the raw database was accepted")
	}
}

func TestFreezeApplyAllSourceRevisionAdvanceExecutionRuntimeRejectsMixedDatabases(t *testing.T) {
	runnerDB := &sql.DB{}
	serviceDB := &sql.DB{}
	runner := &Runner{
		DB:     database.NewConnectionFromDB(runnerDB),
		SvcMgr: newTestServiceGraph(testServiceGraphConfig{DB: serviceDB}),
	}
	if _, err := freezeApplyAllSourceRevisionAdvanceExecutionRuntime(runner); err == nil {
		t.Fatal("service graph from a different raw database was accepted")
	}
}

func testApplyAllSourceRevisionAdvanceExecutionProofRunner(db *sql.DB) *Runner {
	return &Runner{
		DB: database.NewConnectionFromDB(db),
		SvcMgr: &runnerServiceGraph{
			ServiceGraph: newTestServiceGraph(testServiceGraphConfig{
				DB: db, FormulaView: &analytics.FormulaViewService{},
			}),
		},
	}
}
