//go:build integration

package controlplane

import (
	"context"
	"database/sql"
	"encoding/json"
	"os"
	"path/filepath"
	"testing"

	"github.com/pingcap-inc/nexuscrm-controlplane/packs"
	"github.com/pingcap-inc/nexuscrm-controlplane/tenantoverlay"
	"github.com/nexuscrm/db"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
)

func TestTenantOverlayExclusiveSiblingFieldsReachRecordsRuntime(t *testing.T) {
	ctx := context.Background()
	conn, r := setupTenantOverlayExclusiveSiblingRuntime(t, ctx)
	// This test reaches Persistence.Insert/Update/UpsertByExternalID for the
	// full record-write API. Those are exposed on the Runner's service graph
	// (built via the public BuildServiceGraph seam), so reuse it instead of
	// importing the backend composition root's application/services package.
	sm := r.SvcMgr
	defer conn.Close()

	overlayDir := t.TempDir()
	writeTenantExclusiveSiblingFieldsOverlay(t, overlayDir)
	if err := tenantoverlay.New(overlayDir).Apply(ctx, r.PackDeps()); err != nil {
		t.Fatalf("apply tenant overlay: %v", err)
	}
	if err := r.RefreshCache(ctx); err != nil {
		t.Fatalf("refresh runner metadata after tenant overlay: %v", err)
	}
	if err := sm.RefreshMetadataCache(ctx); err != nil {
		t.Fatalf("refresh service manager metadata after tenant overlay: %v", err)
	}

	assertTenantExclusiveSiblingFieldsMetadataStored(t, ctx, conn)

	admin := systemAdminSession()
	writeCtx := constants.WithSecurityContext(ctx, constants.SystemContext, "tenant overlay ExclusiveSiblingFields integration")
	parent, err := sm.Persistence().Insert(writeCtx, "ExclusiveParent__c", models.SObject{
		"Name": "Parent",
	}, admin)
	if err != nil {
		t.Fatalf("insert ExclusiveParent__c: %v", err)
	}
	parentID := recordIDForExclusiveSiblingTenantOverlay(t, parent)

	first, err := sm.Persistence().Insert(writeCtx, "ExclusiveChild__c", models.SObject{
		"Name":          "First",
		"Parent__c":     parentID,
		"Primary__c":    true,
		"ExternalId__c": "line-a",
	}, admin)
	if err != nil {
		t.Fatalf("insert first ExclusiveChild__c: %v", err)
	}
	firstID := recordIDForExclusiveSiblingTenantOverlay(t, first)
	assertTenantExclusiveSiblingPrimary(t, ctx, conn, firstID, true)

	second, err := sm.Persistence().Insert(writeCtx, "ExclusiveChild__c", models.SObject{
		"Name":          "Second",
		"Parent__c":     parentID,
		"Primary__c":    true,
		"ExternalId__c": "line-b",
	}, admin)
	if err != nil {
		t.Fatalf("insert second ExclusiveChild__c: %v", err)
	}
	secondID := recordIDForExclusiveSiblingTenantOverlay(t, second)
	assertTenantExclusiveSiblingPrimary(t, ctx, conn, firstID, false)
	assertTenantExclusiveSiblingPrimary(t, ctx, conn, secondID, true)

	if err := sm.Persistence().Update(writeCtx, "ExclusiveChild__c", firstID, models.SObject{
		"Primary__c": true,
	}, admin); err != nil {
		t.Fatalf("update first ExclusiveChild__c primary: %v", err)
	}
	assertTenantExclusiveSiblingPrimary(t, ctx, conn, firstID, true)
	assertTenantExclusiveSiblingPrimary(t, ctx, conn, secondID, false)

	third, created, err := sm.Persistence().UpsertByExternalID(writeCtx, "ExclusiveChild__c", "ExternalId__c", "line-c", models.SObject{
		"Name":       "Third",
		"Parent__c":  parentID,
		"Primary__c": true,
	}, admin)
	if err != nil {
		t.Fatalf("upsert inserted ExclusiveChild__c by external id: %v", err)
	}
	if !created {
		t.Fatal("upsert line-c created = false, want insert path")
	}
	thirdID := recordIDForExclusiveSiblingTenantOverlay(t, third)
	assertTenantExclusiveSiblingPrimary(t, ctx, conn, firstID, false)
	assertTenantExclusiveSiblingPrimary(t, ctx, conn, thirdID, true)

	_, created, err = sm.Persistence().UpsertByExternalID(writeCtx, "ExclusiveChild__c", "ExternalId__c", "line-b", models.SObject{
		"Name":       "Second promoted",
		"Primary__c": true,
	}, admin)
	if err != nil {
		t.Fatalf("upsert updated ExclusiveChild__c by external id: %v", err)
	}
	if created {
		t.Fatal("upsert line-b created = true, want update path")
	}
	assertTenantExclusiveSiblingPrimary(t, ctx, conn, secondID, true)
	assertTenantExclusiveSiblingPrimary(t, ctx, conn, thirdID, false)
}

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

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

	conn := openIntegrationConnection(t, cfg)
	newConn, err := EnsureL0SchemaDDL(ctx, conn)
	if err != nil {
		_ = conn.Close()
		t.Fatalf("ensure-l0-schema-ddl: %v", err)
	}
	conn = newConn
	if err := verifyNoL0Contamination(ctx, conn.DB()); err != nil {
		_ = conn.Close()
		t.Fatalf("precheck-l0-contamination: %v", err)
	}
	conn, err = ApplyL0ManagedMetadata(ctx, conn)
	if err != nil {
		t.Fatalf("apply-l0-managed-metadata: %v", err)
	}
	if err := RunL0Repair(ctx, conn); err != nil {
		_ = conn.Close()
		t.Fatalf("run-l0-repair: %v", err)
	}

	r, err := NewRunner(conn)
	if err != nil {
		_ = conn.Close()
		t.Fatalf("new runner: %v", err)
	}
	if err := r.RefreshCache(ctx); err != nil {
		_ = conn.Close()
		t.Fatalf("initial cache refresh: %v", err)
	}
	if err := ApplyRuntimeRequiredPacks(ctx, r); err != nil {
		_ = conn.Close()
		t.Fatalf("apply-runtime-required-packs: %v", err)
	}
	if err := packs.RegisterL0RuntimeMetadata(ctx, r.DB.DB()); err != nil {
		_ = conn.Close()
		t.Fatalf("register L0 runtime metadata: %v", err)
	}
	if err := RebuildDerivedL0(ctx, r); err != nil {
		_ = conn.Close()
		t.Fatalf("rebuild-derived-l0: %v", err)
	}
	return r.DB, r
}

func writeTenantExclusiveSiblingFieldsOverlay(t *testing.T, dir string) {
	t.Helper()

	payload := `[
  {
    "apiName": "ExclusiveParent__c",
    "keyPrefix": "xpa",
    "label": "Exclusive Parent",
    "pluralLabel": "Exclusive Parents",
    "tableType": "custom_object",
    "category": "tenant",
    "sharingModel": "Private",
    "fields": [
      {
        "apiName": "Name",
        "label": "Name",
        "type": "string",
        "required": true,
        "isNameField": true
      }
    ]
  },
  {
    "apiName": "ExclusiveChild__c",
    "keyPrefix": "xch",
    "label": "Exclusive Child",
    "pluralLabel": "Exclusive Children",
    "tableType": "custom_object",
    "category": "tenant",
    "sharingModel": "Private",
    "exclusiveSiblingFields": [
      {
        "fieldApiName": "Primary__c",
        "partitionFieldApiName": "Parent__c"
      }
    ],
    "fields": [
      {
        "apiName": "Name",
        "label": "Name",
        "type": "string",
        "required": true,
        "isNameField": true
      },
      {
        "apiName": "Parent__c",
        "label": "Parent",
        "type": "reference",
        "referenceTo": ["ExclusiveParent__c"],
        "relationshipName": "Parent",
        "childRelationshipName": "ExclusiveChildren"
      },
      {
        "apiName": "Primary__c",
        "label": "Primary",
        "type": "boolean"
      },
      {
        "apiName": "ExternalId__c",
        "label": "External ID",
        "type": "string"
      }
    ]
  }
]`
	if err := os.WriteFile(filepath.Join(dir, tenantoverlay.ObjectsSpecFile), []byte(payload), 0o600); err != nil {
		t.Fatalf("write tenant objects spec: %v", err)
	}
}

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

	var stored sql.NullString
	var customized int
	if err := conn.DB().QueryRowContext(ctx, `
		SELECT ExclusiveSiblingFields, COALESCE(ExclusiveSiblingFieldsCustomized, 0)
		FROM _System_Object
		WHERE ApiName = 'ExclusiveChild__c'
	`).Scan(&stored, &customized); err != nil {
		t.Fatalf("query ExclusiveChild__c ExclusiveSiblingFields metadata: %v", err)
	}
	var fields []models.ExclusiveSiblingField
	if !stored.Valid || json.Unmarshal([]byte(stored.String), &fields) != nil {
		t.Fatalf("ExclusiveChild__c ExclusiveSiblingFields = %+v, want tenant overlay declaration", stored)
	}
	if len(fields) != 1 ||
		fields[0].FieldAPIName != "Primary__c" ||
		fields[0].PartitionFieldAPIName != "Parent__c" {
		t.Fatalf("ExclusiveChild__c ExclusiveSiblingFields = %+v, want tenant overlay declaration", fields)
	}
	if customized != 1 {
		t.Fatalf("ExclusiveChild__c ExclusiveSiblingFieldsCustomized = %d, want 1", customized)
	}
}

func assertTenantExclusiveSiblingPrimary(t *testing.T, ctx context.Context, conn *database.TiDBConnection, id string, want bool) {
	t.Helper()

	var got int
	if err := conn.DB().QueryRowContext(ctx,
		"SELECT CAST(COALESCE(`Primary__c`, 0) AS SIGNED) FROM `ExclusiveChild__c` WHERE `Id` = ?",
		id,
	).Scan(&got); err != nil {
		t.Fatalf("query ExclusiveChild__c.Primary__c for %s: %v", id, err)
	}
	wantInt := 0
	if want {
		wantInt = 1
	}
	if got != wantInt {
		t.Fatalf("ExclusiveChild__c %s Primary__c = %d, want %d", id, got, wantInt)
	}
}

func recordIDForExclusiveSiblingTenantOverlay(t *testing.T, record models.SObject) string {
	t.Helper()

	id, _ := record[constants.FieldID].(string)
	if id == "" {
		id, _ = record[constants.ColID].(string)
	}
	if id == "" {
		t.Fatalf("record has no Id: %#v", record)
	}
	return id
}
