package controlplane

import (
	"context"
	"strings"
	"testing"

	"github.com/DATA-DOG/go-sqlmock"

	"github.com/nexuscrm/analytics"
	database "github.com/nexuscrm/db"
	"github.com/nexuscrm/kernel/pkg/logging"
	"github.com/nexuscrm/metadata"
	"github.com/nexuscrm/shared/pkg/models"
	"github.com/pingcap-inc/nexuscrm-controlplane/packs"
)

// Behavioral coverage for the pack materializer's defer branch: the
// never-create contract executed against the real fixture, not AST shape.

func deferMaterializeHarness(t *testing.T) (*Runner, sqlmock.Sqlmock, *packs.SourceBackedPack, func()) {
	t.Helper()
	root := controlplaneTestPackFixtureDir(t, "active-formula-smoke")
	report := packs.ValidateInstallablePackSource("local_path:" + root)
	if report.HasErrors() || report.Pack == nil {
		t.Fatalf("active-formula-smoke fixture is not installable:\n%s", report.Error())
	}
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	schema := activeFormulaSmokeWorkItemSchemaForTest(t, report.Pack)
	metaRepo := &activeFormulaSmokeMetadataRepo{schemas: []*models.ObjectMetadata{schema}}
	metaSvc := metadata.NewMetadataService(metaRepo, nil, nil)
	runner := &Runner{
		DB: database.NewConnectionFromDB(db),
		SvcMgr: newTestServiceGraph(testServiceGraphConfig{
			Metadata:    metaSvc,
			FormulaView: analytics.NewFormulaViewService(db, metaSvc, logging.Default),
		}),
	}
	return runner, mock, report.Pack, func() { db.Close() }
}

func TestDeferMaterializeSkipsExistingViewWithoutCreate(t *testing.T) {
	runner, mock, pack, closeDB := deferMaterializeHarness(t)
	defer closeDB()

	expectTouchedActiveFormulaObjects(mock, "workitem", "WorkItem")
	// Defer existence probe: view exists -> replacement skipped, NO
	// CREATE OR REPLACE is ever expected on this path.
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)[\\s\\S]*information_schema\\.VIEWS").
		WithArgs("v_workitem").
		WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1))
	mock.ExpectQuery("SELECT TABLE_NAME FROM information_schema\\.VIEWS WHERE TABLE_SCHEMA = DATABASE\\(\\) AND TABLE_NAME LIKE 'v\\\\_%'").
		WillReturnRows(sqlmock.NewRows([]string{"TABLE_NAME"}).AddRow("v_workitem"))
	expectTouchedActiveFormulaObjects(mock, "workitem", "WorkItem")
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)[\\s\\S]*information_schema\\.VIEWS").
		WithArgs("v_workitem").
		WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1))
	mock.ExpectQuery("SELECT 1 FROM .v_workitem. LIMIT 1").
		WillReturnRows(sqlmock.NewRows([]string{"1"}))

	if err := materializeSourceBackedPackDerived(context.Background(), runner, pack, true); err != nil {
		t.Fatalf("materialize under defer with existing view = %v, want skip", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations (a CREATE would surface here as unmet/unexpected): %v", err)
	}
}

func TestDeferMaterializeFailsClosedOnMissingView(t *testing.T) {
	runner, mock, pack, closeDB := deferMaterializeHarness(t)
	defer closeDB()

	expectTouchedActiveFormulaObjects(mock, "workitem", "WorkItem")
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)[\\s\\S]*information_schema\\.VIEWS").
		WithArgs("v_workitem").
		WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(0))

	err := materializeSourceBackedPackDerived(context.Background(), runner, pack, true)
	if err == nil {
		t.Fatal("materialize under defer with missing view = nil, want fail-closed")
	}
	if !strings.Contains(err.Error(), "must not introduce") {
		t.Fatalf("error = %v, want the split-release constraint message", err)
	}
}
