//go:build integration

package controlplane

import (
	"context"
	"database/sql"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/pingcap-inc/nexuscrm-controlplane/packs"
)

func TestRuntimeStartupShallowOutcomesOnTiDB(t *testing.T) {
	cfg, cleanup := newTemporaryIntegrationDatabase(t)
	t.Cleanup(cleanup)

	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
	t.Cleanup(cancel)
	conn := initializeControlPlaneMetadata(t, ctx, cfg)
	t.Cleanup(func() { _ = conn.Close() })
	db := conn.DB()

	runner, err := NewRunner(conn)
	if err != nil {
		t.Fatalf("new runner: %v", err)
	}
	if err := runner.RefreshCache(ctx); err != nil {
		t.Fatalf("refresh canonical catalog: %v", err)
	}
	if err := ApplyRuntimeRequiredPacks(ctx, runner); err != nil {
		t.Fatalf("apply runtime-required packs: %v", err)
	}

	const packName = "startup-shallow-outcomes"
	packRoot := writeRuntimeStartupShallowOutcomePack(t)
	if err := InstallPackFromSource(ctx, runner, "local_path:"+packRoot); err != nil {
		t.Fatalf("install outcome pack: %v", err)
	}

	verify := func(t *testing.T, wantError ...string) {
		t.Helper()
		err := packs.VerifyInstalledPersistedRuntimeShallowByNameWithComponentKindRegistrationSet(
			ctx, db, packName, packs.AppPack, packs.ComponentKindRegistrationSet{},
		)
		if len(wantError) == 0 {
			if err != nil {
				t.Fatalf("startup-shallow verification: %v", err)
			}
			return
		}
		if err == nil {
			t.Fatalf("startup-shallow verification = nil, want %q", wantError)
		}
		for _, fragment := range wantError {
			if !strings.Contains(err.Error(), fragment) {
				t.Fatalf("startup-shallow verification = %v, want %q", err, fragment)
			}
		}
	}
	verify(t)

	t.Run("permission projection and orphan ownership", func(t *testing.T) {
		t.Cleanup(func() {
			_, _ = db.ExecContext(context.Background(), `UPDATE _System_Permission
				SET Label = 'Startup Probe Access' WHERE ApiName = 'StartupProbeAccess'`)
			_, _ = db.ExecContext(context.Background(), `DELETE FROM _System_Permission WHERE Id = 'startup-shallow-extra-permission'`)
		})
		mustExecRuntimeStartupShallow(t, ctx, db, "drift permission label", `UPDATE _System_Permission SET Label = 'Drifted' WHERE ApiName = 'StartupProbeAccess'`)
		verify(t, "permission StartupProbeAccess projection drift")
		mustExecRuntimeStartupShallow(t, ctx, db, "restore permission label", `UPDATE _System_Permission SET Label = 'Startup Probe Access' WHERE ApiName = 'StartupProbeAccess'`)
		verify(t)

		mustExecRuntimeStartupShallow(t, ctx, db, "insert undeclared permission", `INSERT INTO _System_Permission
			(Id, ApiName, Label, Category, Description, IsSystem, IsActive, OwnerPack, CreatedDate, LastModifiedDate)
			VALUES ('startup-shallow-extra-permission', 'StartupProbeExtra', 'Startup Probe Extra', 'System', '', 0, 1, ?, NOW(), NOW())`, packName)
		t.Cleanup(func() {
			_, _ = db.ExecContext(context.Background(), `DELETE FROM _System_Permission WHERE Id = 'startup-shallow-extra-permission'`)
		})
		verify(t, "permission StartupProbeExtra is undeclared")
		mustExecRuntimeStartupShallow(t, ctx, db, "delete undeclared permission", `DELETE FROM _System_Permission WHERE Id = 'startup-shallow-extra-permission'`)
		verify(t)
	})

	t.Run("validation-rule projection and retained customization", func(t *testing.T) {
		t.Cleanup(func() {
			_, _ = db.ExecContext(context.Background(), `UPDATE _System_ValidationRule
				SET Active = 1, IsCustomized = 0, `+"`Condition`"+` = 'ISBLANK(Name)', ErrorMessage = 'Name is required'
				WHERE OwnerPack = ? AND ObjectApiName = 'StartupProbe' AND Name = 'StartupProbe_Requires_Name'`, packName)
		})
		for _, drift := range []struct {
			name    string
			setExpr string
		}{
			{name: "condition", setExpr: "`Condition` = 'FALSE'"},
			{name: "error message", setExpr: "ErrorMessage = 'Drifted message'"},
			{name: "active", setExpr: "Active = 0"},
		} {
			t.Run(drift.name, func(t *testing.T) {
				mustExecRuntimeStartupShallow(t, ctx, db, "drift validation rule", `UPDATE _System_ValidationRule SET `+drift.setExpr+`
					WHERE OwnerPack = ? AND ObjectApiName = 'StartupProbe' AND Name = 'StartupProbe_Requires_Name'`, packName)
				verify(t, "validation_rule StartupProbe/StartupProbe_Requires_Name projection drift")
				mustExecRuntimeStartupShallow(t, ctx, db, "restore validation rule", `UPDATE _System_ValidationRule
					SET Active = 1, IsCustomized = 0, `+"`Condition`"+` = 'ISBLANK(Name)', ErrorMessage = 'Name is required'
					WHERE OwnerPack = ? AND ObjectApiName = 'StartupProbe' AND Name = 'StartupProbe_Requires_Name'`, packName)
				verify(t)
			})
		}

		mustExecRuntimeStartupShallow(t, ctx, db, "customize and deactivate validation rule", `UPDATE _System_ValidationRule
			SET Active = 0, IsCustomized = 1, `+"`Condition`"+` = 'FALSE', ErrorMessage = 'Customized message'
			WHERE OwnerPack = ? AND ObjectApiName = 'StartupProbe' AND Name = 'StartupProbe_Requires_Name'`, packName)
		verify(t)
		mustExecRuntimeStartupShallow(t, ctx, db, "restore validation rule activity", `UPDATE _System_ValidationRule
			SET Active = 1, IsCustomized = 0, `+"`Condition`"+` = 'ISBLANK(Name)', ErrorMessage = 'Name is required'
			WHERE OwnerPack = ? AND ObjectApiName = 'StartupProbe' AND Name = 'StartupProbe_Requires_Name'`, packName)
	})

	t.Run("list-fields projection and defaults-only override", func(t *testing.T) {
		t.Cleanup(func() {
			_, _ = db.ExecContext(context.Background(), `UPDATE _System_Object SET
				ListFields = CASE ApiName
					WHEN 'StartupProbe' THEN JSON_ARRAY('Name', 'Status')
					WHEN 'StartupEmptyListProbe' THEN JSON_ARRAY()
					WHEN 'StartupObjectSpecListProbe' THEN JSON_ARRAY('Name')
				END,
				ListFieldsCustomized = 0
				WHERE ApiName IN ('StartupProbe', 'StartupEmptyListProbe', 'StartupObjectSpecListProbe')`)
		})
		mustExecRuntimeStartupShallow(t, ctx, db, "drift list fields", `UPDATE _System_Object
			SET ListFields = JSON_ARRAY('Name') WHERE ApiName = 'StartupProbe'`)
		verify(t, "list_fields StartupProbe projection drift")
		mustExecRuntimeStartupShallow(t, ctx, db, "customize list fields", `UPDATE _System_Object
			SET ListFieldsCustomized = 1 WHERE ApiName = 'StartupProbe'`)
		verify(t)
		mustExecRuntimeStartupShallow(t, ctx, db, "restore list fields", `UPDATE _System_Object
			SET ListFields = JSON_ARRAY('Name', 'Status'), ListFieldsCustomized = 0 WHERE ApiName = 'StartupProbe'`)
		verify(t)

		mustExecRuntimeStartupShallow(t, ctx, db, "drift explicit empty list fields", `UPDATE _System_Object
			SET ListFields = JSON_ARRAY('Name') WHERE ApiName = 'StartupEmptyListProbe'`)
		verify(t, "list_fields StartupEmptyListProbe projection drift")
		mustExecRuntimeStartupShallow(t, ctx, db, "restore explicit empty list fields", `UPDATE _System_Object
			SET ListFields = JSON_ARRAY() WHERE ApiName = 'StartupEmptyListProbe'`)
		verify(t)

		mustExecRuntimeStartupShallow(t, ctx, db, "drift object-spec list fields", `UPDATE _System_Object
			SET ListFields = JSON_ARRAY() WHERE ApiName = 'StartupObjectSpecListProbe'`)
		verify(t, "list_fields StartupObjectSpecListProbe projection drift")
		mustExecRuntimeStartupShallow(t, ctx, db, "restore object-spec list fields", `UPDATE _System_Object
			SET ListFields = JSON_ARRAY('Name') WHERE ApiName = 'StartupObjectSpecListProbe'`)
		verify(t)
	})

	t.Run("record-type projection and extra live row", func(t *testing.T) {
		for _, drift := range []struct {
			name      string
			setExpr   string
			wantError string
		}{
			{name: "developer name", setExpr: "DeveloperName = 'Drifted'", wantError: "record_type StartupProbe/Drifted is undeclared"},
			{name: "sobject type", setExpr: "SobjectType = 'OtherObject'", wantError: "record_type StartupProbe/Primary projection drift"},
			{name: "name", setExpr: "Name = 'Drifted'", wantError: "record_type StartupProbe/Primary projection drift"},
			{name: "active", setExpr: "IsActive = 0", wantError: "record_type StartupProbe/Primary projection drift"},
			{name: "owner pack", setExpr: "OwnerPack = 'other-pack'", wantError: "record_type StartupProbe/Primary projection drift"},
		} {
			t.Run(drift.name, func(t *testing.T) {
				t.Cleanup(func() {
					_, _ = db.ExecContext(context.Background(), `UPDATE _System_RecordType
						SET Name = 'Primary', DeveloperName = 'Primary', SobjectType = 'StartupProbe', IsActive = 1, OwnerPack = ?
						WHERE ObjectId = (SELECT Id FROM _System_Object WHERE ApiName = 'StartupProbe')`, packName)
				})
				mustExecRuntimeStartupShallow(t, ctx, db, "drift record type", `UPDATE _System_RecordType SET `+drift.setExpr+`
					WHERE ObjectId = (SELECT Id FROM _System_Object WHERE ApiName = 'StartupProbe')
					  AND (Name = 'Primary' OR DeveloperName = 'Primary')`)
				verify(t, drift.wantError)
				mustExecRuntimeStartupShallow(t, ctx, db, "restore record type", `UPDATE _System_RecordType
					SET Name = 'Primary', DeveloperName = 'Primary', SobjectType = 'StartupProbe', IsActive = 1, OwnerPack = ?
					WHERE ObjectId = (SELECT Id FROM _System_Object WHERE ApiName = 'StartupProbe')`, packName)
				verify(t)
			})
		}

		mustExecRuntimeStartupShallow(t, ctx, db, "insert undeclared record type", `INSERT INTO _System_RecordType
			(Id, ObjectId, Name, DeveloperName, SobjectType, IsActive, IsMaster, IsDeleted, OwnerPack, CreatedDate, LastModifiedDate)
			SELECT 'startup-shallow-extra-record-type', Id, 'Extra', 'Extra', ApiName, 1, 0, 0, ?, NOW(), NOW()
			FROM _System_Object WHERE ApiName = 'StartupProbe'`, packName)
		t.Cleanup(func() {
			_, _ = db.ExecContext(context.Background(), `DELETE FROM _System_RecordType WHERE Id = 'startup-shallow-extra-record-type'`)
		})
		verify(t, "record_type StartupProbe/Extra is undeclared")
		mustExecRuntimeStartupShallow(t, ctx, db, "delete undeclared record type", `DELETE FROM _System_RecordType WHERE Id = 'startup-shallow-extra-record-type'`)
		verify(t)
	})
}

func mustExecRuntimeStartupShallow(t *testing.T, ctx context.Context, db *sql.DB, label, statement string, args ...any) {
	t.Helper()
	if _, err := db.ExecContext(ctx, statement, args...); err != nil {
		t.Fatalf("%s: %v", label, err)
	}
}

func writeRuntimeStartupShallowOutcomePack(t *testing.T) string {
	t.Helper()
	root := t.TempDir()
	manifest := `{
  "manifestFormatVersion": "1",
  "name": "startup-shallow-outcomes",
  "displayName": "Startup Shallow Outcomes",
  "category": "app-pack",
  "version": "0.1.0",
  "platformCompatibility": {"min": "0.2.0", "maxExclusive": "0.3.0"},
  "dependencies": [],
  "components": [
    {
      "kind": "object_spec",
      "businessKey": "startup-probe",
      "manageability": "locked",
      "payload": [{
        "apiName": "StartupProbe",
        "label": "Startup Probe",
        "pluralLabel": "Startup Probes",
        "tableType": "standard_object",
        "category": "test",
        "sharingModel": "Private",
        "enableHierarchySharing": false,
        "fields": [
          {"apiName": "Name", "label": "Name", "type": "string", "required": true, "isNameField": true},
          {"apiName": "Status", "label": "Status", "type": "string"}
        ]
      }, {
        "apiName": "StartupEmptyListProbe",
        "label": "Startup Empty List Probe",
        "pluralLabel": "Startup Empty List Probes",
        "tableType": "standard_object",
        "category": "test",
        "sharingModel": "Private",
        "enableHierarchySharing": false,
        "fields": [{"apiName": "Name", "label": "Name", "type": "string", "required": true, "isNameField": true}]
      }, {
        "apiName": "StartupObjectSpecListProbe",
        "label": "Startup Object Spec List Probe",
        "pluralLabel": "Startup Object Spec List Probes",
        "tableType": "standard_object",
        "category": "test",
        "sharingModel": "Private",
        "enableHierarchySharing": false,
        "listFields": ["Name"],
        "fields": [{"apiName": "Name", "label": "Name", "type": "string", "required": true, "isNameField": true}]
      }]
    },
    {
      "kind": "permission",
      "businessKey": "startup-probe-permission",
      "manageability": "defaults_only",
      "payload": [{"apiName":"StartupProbeAccess","label":"Startup Probe Access","category":"System","description":"Access startup probe"}]
    },
    {
      "kind": "validation_rule",
      "businessKey": "startup-probe-validation",
      "manageability": "defaults_only",
      "dependsOn": [{"kind":"object_spec","businessKey":"startup-probe"}],
      "payload": {"validationRules":[{
        "id":"vrule_startup_probe_requires_name",
        "objectApiName":"StartupProbe",
        "name":"StartupProbe_Requires_Name",
        "active":true,
        "condition":"ISBLANK(Name)",
        "errorMessage":"Name is required"
      }]}
    },
    {
      "kind": "list_fields",
      "businessKey": "startup-probe-list-fields",
      "manageability": "defaults_only",
      "dependsOn": [{"kind":"object_spec","businessKey":"startup-probe"}],
      "payload": {"StartupProbe":["Name","Status"],"StartupEmptyListProbe":[]}
    },
    {
      "kind": "record_type",
      "businessKey": "startup-probe-record-types",
      "manageability": "locked",
      "dependsOn": [{"kind":"object_spec","businessKey":"startup-probe"}],
      "payload": {"recordTypes":[{"objectApiName":"StartupProbe","types":[{"name":"Primary"}]}]}
    }
  ]
}`
	if err := os.WriteFile(filepath.Join(root, "pack.json"), []byte(manifest), 0o644); err != nil {
		t.Fatalf("write startup-shallow outcome pack: %v", err)
	}
	return root
}
