//go:build integration

package controlplane

import (
	"context"
	"strings"
	"testing"

	"github.com/nexuscrm/db"
	"github.com/nexuscrm/shared/pkg/models"
)

func TestOrderActivationDeniedWithoutContractUsesValidationMetadata(t *testing.T) {
	ctx := context.Background()
	conn, sm := setupCRMRuntimeForOrderActivation(t, ctx)
	defer conn.Close()

	admin := systemAdminSession()
	disableValidationRuleByName(t, ctx, sm, "Order_Activate_Contract_Start")
	disableValidationRuleByName(t, ctx, sm, "Order_Activate_Contract_End")
	accountID := createAccountForOrderActivation(t, ctx, sm, admin)
	orderID := createOrderForOrderActivation(t, ctx, sm, admin, accountID, "", "")

	err := sm.Persistence().Update(ctx, "Order", orderID, models.SObject{"Status": "Activated"}, admin)
	if err == nil || !strings.Contains(err.Error(), "no Contract is associated") {
		t.Fatalf("activate order without contract error = %v, want missing-contract validation", err)
	}
}

func TestOrderActivationAllowedStampsFieldsViaAuthoritativePath(t *testing.T) {
	ctx := context.Background()
	conn, sm := setupCRMRuntimeForOrderActivation(t, ctx)
	defer conn.Close()

	admin := systemAdminSession()
	accountID := createAccountForOrderActivation(t, ctx, sm, admin)
	contractID := createContractForOrderActivation(t, ctx, sm, admin, accountID)
	orderID := createOrderForOrderActivation(t, ctx, sm, admin, accountID, contractID, "2026-06-30")

	if err := sm.Persistence().Update(ctx, "Order", orderID, models.SObject{"Status": "Activated"}, admin); err != nil {
		t.Fatalf("activate order: %v", err)
	}

	order, err := sm.Persistence().GetRaw(ctx, "Order", orderID)
	if err != nil {
		t.Fatalf("get activated order: %v", err)
	}
	if got := order["Status"]; got != "Activated" {
		t.Fatalf("Order.Status = %#v, want Activated", got)
	}
	if got := order["StatusCode"]; got != "Activated" {
		t.Fatalf("Order.StatusCode = %#v, want Activated", got)
	}
	if got := order["ActivatedById"]; got != admin.ID {
		t.Fatalf("Order.ActivatedById = %#v, want %s", got, admin.ID)
	}
	if got := order["ActivatedDate"]; got == nil || got == "" {
		t.Fatalf("Order.ActivatedDate = %#v, want non-empty stamp", got)
	}
}

func TestOrderActivationPreconditionsFollowValidationMetadataAuthority(t *testing.T) {
	ctx := context.Background()
	conn, sm := setupCRMRuntimeForOrderActivation(t, ctx)
	defer conn.Close()

	admin := systemAdminSession()
	disableValidationRuleByName(t, ctx, sm, "Order_Activate_Requires_Contract")
	disableValidationRuleByName(t, ctx, sm, "Order_Activate_Contract_Start")
	disableValidationRuleByName(t, ctx, sm, "Order_Activate_Contract_End")

	accountID := createAccountForOrderActivation(t, ctx, sm, admin)
	orderID := createOrderForOrderActivation(t, ctx, sm, admin, accountID, "", "")

	if err := sm.Persistence().Update(ctx, "Order", orderID, models.SObject{"Status": "Activated"}, admin); err != nil {
		t.Fatalf("activate order after disabling activation precondition rules: %v", err)
	}
}

func TestOrderActivationSideEffectsFollowFlowAuthority(t *testing.T) {
	ctx := context.Background()
	conn, sm := setupCRMRuntimeForOrderActivation(t, ctx)
	defer conn.Close()

	admin := systemAdminSession()
	disableFlowByName(t, ctx, sm, "Std_OrderActivateStamp")

	accountID := createAccountForOrderActivation(t, ctx, sm, admin)
	contractID := createContractForOrderActivation(t, ctx, sm, admin, accountID)
	orderID := createOrderForOrderActivation(t, ctx, sm, admin, accountID, contractID, "2026-06-30")

	if err := sm.Persistence().Update(ctx, "Order", orderID, models.SObject{"Status": "Activated"}, admin); err != nil {
		t.Fatalf("activate order with flow disabled: %v", err)
	}

	order, err := sm.Persistence().GetRaw(ctx, "Order", orderID)
	if err != nil {
		t.Fatalf("get activated order: %v", err)
	}
	if got := order["Status"]; got != "Activated" {
		t.Fatalf("Order.Status = %#v, want Activated", got)
	}
	if got := order["StatusCode"]; got == "Activated" {
		t.Fatalf("Order.StatusCode = %#v, want unstamped value when flow disabled", got)
	}
	if got := order["ActivatedById"]; got != nil && got != "" {
		t.Fatalf("Order.ActivatedById = %#v, want no stamp when flow disabled", got)
	}
	if got := order["ActivatedDate"]; got != nil && got != "" {
		t.Fatalf("Order.ActivatedDate = %#v, want no stamp when flow disabled", got)
	}
}

func setupCRMRuntimeForOrderActivation(t *testing.T, ctx context.Context) (*database.TiDBConnection, ServiceGraph) {
	t.Helper()

	cfg, cleanup := newTemporaryIntegrationDatabase(t)
	t.Cleanup(cleanup)
	setDatabaseEnvFromConfig(t, cfg)

	conn := openIntegrationConnection(t, cfg)
	if err := InitL0(ctx, conn); err != nil {
		_ = conn.Close()
		t.Fatalf("init-l0: %v", err)
	}
	_ = conn.Close()

	conn = openIntegrationConnection(t, cfg)
	r, err := NewRunner(conn)
	if err != nil {
		t.Fatalf("new runner: %v", err)
	}
	if err := r.RefreshCache(ctx); err != nil {
		t.Fatalf("initial cache refresh: %v", err)
	}
	if err := ApplyPacks(ctx, r, false); err != nil {
		t.Fatalf("apply packs: %v", err)
	}

	// Reuse the Runner's service graph (built via the public BuildServiceGraph
	// seam) as the record-setup graph; it is constructed from the same
	// infrastructure deps a standalone ServiceManager would be.
	sm := r.SvcMgr
	if err := sm.RefreshMetadataCache(ctx); err != nil {
		t.Fatalf("runtime metadata refresh: %v", err)
	}
	return conn, sm
}

// systemAdminSession is defined once (untagged) in active_formula_smoke_test.go
// and shared across the package's integration tests. The previous duplicate here
// made `go test -tags=integration ./internal/controlplane/...` fail to compile
// (redeclaration); it went undetected because no CI builds the integration tag.

func createAccountForOrderActivation(t *testing.T, ctx context.Context, sm ServiceGraph, user *models.UserSession) string {
	t.Helper()
	account, err := sm.Persistence().Insert(ctx, "Account", models.SObject{
		"Name": "Sample Account",
	}, user)
	if err != nil {
		t.Fatalf("create account: %v", err)
	}
	id, _ := account["Id"].(string)
	if id == "" {
		t.Fatal("create account returned empty Id")
	}
	return id
}

func createContractForOrderActivation(t *testing.T, ctx context.Context, sm ServiceGraph, user *models.UserSession, accountID string) string {
	t.Helper()
	contract, err := sm.Persistence().Insert(ctx, "Contract", models.SObject{
		"AccountId":    accountID,
		"Status":       "Activated",
		"StartDate":    "2026-01-01",
		"EndDate":      "2026-12-31",
		"ContractTerm": 12,
	}, user)
	if err != nil {
		t.Fatalf("create contract: %v", err)
	}
	id, _ := contract["Id"].(string)
	if id == "" {
		t.Fatal("create contract returned empty Id")
	}
	return id
}

func createOrderForOrderActivation(t *testing.T, ctx context.Context, sm ServiceGraph, user *models.UserSession, accountID, contractID, endDate string) string {
	t.Helper()
	data := models.SObject{
		"AccountId":     accountID,
		"Status":        "Draft",
		"EffectiveDate": "2026-06-01",
	}
	if endDate != "" {
		data["EndDate"] = endDate
	}
	if contractID != "" {
		data["ContractId"] = contractID
	}
	order, err := sm.Persistence().Insert(ctx, "Order", data, user)
	if err != nil {
		t.Fatalf("create order: %v", err)
	}
	id, _ := order["Id"].(string)
	if id == "" {
		t.Fatal("create order returned empty Id")
	}
	return id
}

func disableValidationRuleByName(t *testing.T, ctx context.Context, sm ServiceGraph, ruleName string) {
	t.Helper()
	var target *models.ValidationRule
	for _, rule := range sm.Metadata().GetValidationRules(ctx, "Order") {
		if rule.Name == ruleName {
			target = rule
			break
		}
	}
	if target == nil {
		t.Fatalf("validation rule %s not found", ruleName)
	}
	if err := sm.Metadata().UpdateValidationRule(ctx, target.ID, &models.ValidationRule{Active: false}); err != nil {
		t.Fatalf("disable validation rule %s: %v", ruleName, err)
	}
	if err := sm.RefreshMetadataCache(ctx); err != nil {
		t.Fatalf("refresh metadata after disabling validation rule: %v", err)
	}
}

func disableFlowByName(t *testing.T, ctx context.Context, sm ServiceGraph, flowName string) {
	t.Helper()
	def := sm.Metadata().GetFlowDefinitionByName(ctx, flowName)
	if def == nil {
		t.Fatalf("flow definition %s not found", flowName)
	}
	if def.ActiveVersionId == "" {
		t.Fatalf("flow definition %s has no active version", flowName)
	}
	if err := sm.Metadata().DeactivateFlowVersion(ctx, def.ActiveVersionId); err != nil {
		t.Fatalf("deactivate flow %s: %v", flowName, err)
	}
	if err := sm.RefreshMetadataCache(ctx); err != nil {
		t.Fatalf("refresh metadata after disabling flow: %v", err)
	}
}
