package dialectsfcrm

import (
	"context"
	"net/http"
	"testing"

	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/contract"
	"github.com/nexuscrm/shared/pkg/dialect"
	"github.com/nexuscrm/shared/pkg/models"
)

// Phase-2 L0-B PR-0b (goldens-first) capture-and-freeze regression.
//
// The existing golden_test.go drives DescribeGlobal/DescribeObject/
// DescribeSystemFile success bodies but asserts them only by TYPED-STRUCT field
// probes (body.Name, body.KeyPrefix, body.Fields[1].Name, ...). Those probes do
// NOT pin the full marshalled wire JSON: a drift in a non-probed field, a key
// order change, an omitempty regression, or a URL grammar change in the success
// body would slip through. This test BYTE-pins the complete marshalled v63
// success JSON for the same three neutral handlers, reusing the exact harness,
// fakes, and deps builder already defined in golden_test.go (fakeDescribeMetadata,
// fakeDescribePolicy, dialectDescribeDeps, mustJSON, stringPtr).
//
// The frozen literals were captured from the CURRENT dialect output (apiVersion
// v63.0) with the same inputs the typed-probe tests use. Regenerate intentionally
// (only on a deliberate, reviewed wire change) by printing mustJSON(resp.Body).
//
// ZERO production change: this file only drives the existing exported neutral
// handlers and asserts equality. It modifies no production .go.

// assertDescribeBody pins resp.Body's marshalled JSON to a frozen literal oracle.
func assertDescribeBody(t *testing.T, name string, body any, wantLiteral string) {
	t.Helper()
	got := mustJSON(t, body)
	if got != wantLiteral {
		t.Fatalf("%s success body drifted from frozen v63 bytes:\n got: %s\nwant: %s", name, got, wantLiteral)
	}
}

// TestDescribeGlobalNeutralHandlerSuccessByteGolden byte-pins the DescribeGlobal
// success body (same inputs as TestDescribeGlobalNeutralHandlerUsesMetadataAndPolicyContracts).
func TestDescribeGlobalNeutralHandlerSuccessByteGolden(t *testing.T) {
	metadata := &fakeDescribeMetadata{
		objects: []models.ObjectMetadata{
			{
				APIName:      "Account",
				Label:        "Account",
				PluralLabel:  "Accounts",
				Searchable:   true,
				SharingModel: constants.SharingModelPublicReadWrite,
				TableType:    constants.TableTypeStandardObject,
			},
			{
				APIName:     "SecretObject",
				Label:       "Secret",
				PluralLabel: "Secrets",
				Searchable:  true,
			},
		},
		keyPrefixes: map[string]string{"Account": "001"},
	}
	policy := &fakeDescribePolicy{access: map[string]*contract.EffectiveObjectAccess{
		"Account":      {Object: contract.ObjectAccess{Create: true, Read: true, Update: true, Delete: false}},
		"SecretObject": {Object: contract.ObjectAccess{Read: false}},
	}}

	resp, err := DescribeGlobalNeutralHandler(context.Background(), &dialect.Request{
		Version: "v63.0",
		User:    &models.UserSession{ID: "005"},
	}, dialectDescribeDeps(metadata, policy))
	if err != nil {
		t.Fatalf("DescribeGlobalNeutralHandler error = %v", err)
	}
	if resp.Status != http.StatusOK {
		t.Fatalf("status = %d, want 200", resp.Status)
	}
	assertDescribeBody(t, "describe-global", resp.Body, goldenDescribeGlobalSuccessV63)
}

// TestDescribeObjectNeutralHandlerSuccessByteGolden byte-pins the DescribeObject
// success body (same inputs as TestDescribeObjectNeutralHandlerProjectsFieldsRecordTypesAndRelationships).
func TestDescribeObjectNeutralHandlerSuccessByteGolden(t *testing.T) {
	account := models.ObjectMetadata{
		APIName:      "Account",
		Label:        "Account",
		PluralLabel:  "Accounts",
		Searchable:   true,
		SharingModel: constants.SharingModelPublicReadWrite,
		TableType:    constants.TableTypeStandardObject,
		Fields: []models.FieldMetadata{
			{APIName: "Id", Label: "Account ID", Type: constants.FieldTypeString, IsSystem: true},
			{APIName: "Name", Label: "Account Name", Type: constants.FieldTypeString, IsNameField: true},
		},
	}
	contact := models.ObjectMetadata{
		APIName:     "Contact",
		Label:       "Contact",
		PluralLabel: "Contacts",
		Fields: []models.FieldMetadata{{
			APIName:               "AccountId",
			Label:                 "Account",
			Type:                  constants.FieldTypeReference,
			ReferenceTo:           []string{"Account"},
			ChildRelationshipName: stringPtr("Contacts"),
		}},
	}
	metadata := &fakeDescribeMetadata{
		objects:     []models.ObjectMetadata{account, contact},
		schemas:     map[string]*models.ObjectMetadata{"Account": &account, "Contact": &contact},
		keyPrefixes: map[string]string{"Account": "001", "Contact": "003"},
		children:    map[string][]*models.ObjectMetadata{"Account": {&contact}},
		relationships: map[string][]*models.Relationship{
			"Contact": {{
				ParentObjectAPIName: "Account",
				ChildObjectAPIName:  "Contact",
				FieldAPIName:        "AccountId",
			}},
		},
	}
	policy := &fakeDescribePolicy{access: map[string]*contract.EffectiveObjectAccess{
		"Account": {
			Object: contract.ObjectAccess{Create: true, Read: true, Update: true, Delete: true},
			Fields: map[string]contract.FieldAccess{
				"Id":   {Readable: true},
				"Name": {Createable: true, Updateable: true, Readable: true},
			},
			RecordTypes: []contract.RecordTypeAvailability{{
				ID:        "012000000000000AAA",
				APIName:   "Master",
				Name:      "Master",
				Available: true,
				Master:    true,
				Default:   false,
			}, {
				ID:        "012-business",
				APIName:   "Business",
				Name:      "Business",
				Available: true,
				Master:    false,
				Default:   true,
			}},
			DefaultRecordTypeID:    "012-business",
			HasConcreteRecordTypes: true,
			AvailableConcreteCount: 1,
		},
	}}

	resp, err := DescribeObjectNeutralHandler(context.Background(), &dialect.Request{
		Version: "v63.0",
		User:    &models.UserSession{ID: "005"},
		Params:  map[string]string{"sobject": "Account"},
	}, dialectDescribeDeps(metadata, policy))
	if err != nil {
		t.Fatalf("DescribeObjectNeutralHandler error = %v", err)
	}
	if resp.Status != http.StatusOK {
		t.Fatalf("status = %d, want 200", resp.Status)
	}
	assertDescribeBody(t, "describe-object", resp.Body, goldenDescribeObjectSuccessV63)
}

// TestDescribeSystemFileNeutralHandlerSuccessByteGolden byte-pins the
// DescribeSystemFile success body (same inputs as
// TestDescribeSystemFileNeutralHandlerPinsStaticRouteToSameDescribeMapper).
func TestDescribeSystemFileNeutralHandlerSuccessByteGolden(t *testing.T) {
	systemFile := models.ObjectMetadata{
		APIName:     "_System_File",
		Label:       "File",
		PluralLabel: "Files",
		Fields: []models.FieldMetadata{
			{APIName: "Id", Label: "File ID", Type: constants.FieldTypeString, IsSystem: true},
		},
	}
	metadata := &fakeDescribeMetadata{
		schemas:     map[string]*models.ObjectMetadata{"_System_File": &systemFile},
		keyPrefixes: map[string]string{"_System_File": "068"},
	}
	policy := &fakeDescribePolicy{access: map[string]*contract.EffectiveObjectAccess{
		"_System_File": {
			Object: contract.ObjectAccess{Read: true},
			Fields: map[string]contract.FieldAccess{"Id": {Readable: true}},
		},
	}}

	resp, err := DescribeSystemFileNeutralHandler(context.Background(), &dialect.Request{
		Version: "v63.0",
		Params:  map[string]string{},
	}, dialectDescribeDeps(metadata, policy))
	if err != nil {
		t.Fatalf("DescribeSystemFileNeutralHandler error = %v", err)
	}
	if resp.Status != http.StatusOK {
		t.Fatalf("status = %d, want 200", resp.Status)
	}
	assertDescribeBody(t, "describe-system-file", resp.Body, goldenDescribeSystemFileSuccessV63)
}

// Frozen v63 success bodies. Captured from the current dialect output with the
// inputs above. Regenerate only on a deliberate, reviewed wire change.
const goldenDescribeGlobalSuccessV63 = `{"encoding":"UTF-8","maxBatchSize":200,"sobjects":[{"activateable":false,"associateEntityType":null,"associateParentEntity":null,"createable":true,"custom":false,"customSetting":false,"deletable":false,"deprecatedAndHidden":false,"feedEnabled":true,"hasSubtypes":false,"isSubtype":false,"keyPrefix":"001","label":"Account","labelPlural":"Accounts","layoutable":true,"mergeable":false,"mruEnabled":true,"name":"Account","isSystem":false,"queryable":true,"replicateable":true,"retrieveable":true,"searchable":true,"sharingModel":"PublicReadWrite","tableType":"standard_object","triggerable":true,"undeletable":true,"updateable":true,"urls":{"describe":"/services/data/v63.0/sobjects/Account/describe","rowTemplate":"/services/data/v63.0/sobjects/Account/{ID}","sobject":"/services/data/v63.0/sobjects/Account"}}]}`

const goldenDescribeObjectSuccessV63 = `{"actionOverrides":[],"activateable":false,"associateEntityType":null,"associateParentEntity":null,"childRelationships":[{"cascadeDelete":false,"childSObject":"Contact","deprecatedAndHidden":false,"field":"AccountId","junctionIdListNames":[],"junctionReferenceTo":[],"relationshipName":"Contacts","restrictedDelete":true}],"compactLayoutable":true,"createable":true,"custom":false,"customSetting":false,"deletable":true,"deepCloneable":false,"deprecatedAndHidden":false,"feedEnabled":true,"fields":[{"aggregatable":true,"aiPredictionField":false,"autoNumber":false,"byteLength":18,"calculated":false,"calculatedFormula":null,"cascadeDelete":false,"caseSensitive":false,"compoundFieldName":null,"controllerName":null,"createable":false,"custom":false,"defaultValue":null,"defaultValueFormula":null,"defaultedOnCreate":false,"dependentPicklist":false,"deprecatedAndHidden":false,"digits":0,"displayLocationInDecimal":false,"encrypted":false,"externalId":false,"extraTypeInfo":null,"filterable":true,"filteredLookupInfo":null,"formulaTreatNullNumberAsZero":false,"groupable":true,"highScaleNumber":false,"htmlFormatted":false,"idLookup":true,"inlineHelpText":null,"label":"Account ID","length":18,"mask":null,"maskType":null,"name":"Id","nameField":false,"namePointing":false,"nillable":true,"permissionable":true,"picklistValues":[],"polymorphicForeignKey":false,"precision":0,"queryByDistance":false,"readable":true,"referenceTargetField":null,"referenceTo":[],"relationshipName":null,"relationshipOrder":null,"restrictedDelete":false,"restrictedPicklist":false,"scale":0,"searchPrefilterable":true,"soapType":"xsd:string","sortable":true,"type":"id","unique":false,"updateable":false,"writeRequiresMasterRead":false},{"aggregatable":true,"aiPredictionField":false,"autoNumber":false,"byteLength":255,"calculated":false,"calculatedFormula":null,"cascadeDelete":false,"caseSensitive":false,"compoundFieldName":null,"controllerName":null,"createable":true,"custom":true,"defaultValue":null,"defaultValueFormula":null,"defaultedOnCreate":false,"dependentPicklist":false,"deprecatedAndHidden":false,"digits":0,"displayLocationInDecimal":false,"encrypted":false,"externalId":false,"extraTypeInfo":null,"filterable":true,"filteredLookupInfo":null,"formulaTreatNullNumberAsZero":false,"groupable":true,"highScaleNumber":false,"htmlFormatted":false,"idLookup":false,"inlineHelpText":null,"label":"Account Name","length":255,"mask":null,"maskType":null,"name":"Name","nameField":true,"namePointing":false,"nillable":true,"permissionable":true,"picklistValues":[],"polymorphicForeignKey":false,"precision":0,"queryByDistance":false,"readable":true,"referenceTargetField":null,"referenceTo":[],"relationshipName":null,"relationshipOrder":null,"restrictedDelete":false,"restrictedPicklist":false,"scale":0,"searchPrefilterable":true,"soapType":"xsd:string","sortable":true,"type":"string","unique":false,"updateable":true,"writeRequiresMasterRead":false}],"hasSubtypes":false,"isSubtype":false,"keyPrefix":"001","label":"Account","labelPlural":"Accounts","layoutable":true,"displayNameField":"Name","listviewable":null,"lookupLayoutable":null,"mergeable":false,"mruEnabled":true,"name":"Account","namedLayoutInfos":[],"networkScopeFieldName":null,"queryable":true,"recordTypeInfos":[{"active":true,"available":true,"defaultRecordTypeMapping":true,"developerName":"Business","master":false,"name":"Business","recordTypeId":"012-business","urls":{"layout":"/services/data/v63.0/sobjects/Account/describe/layouts/012-business"}}],"replicateable":true,"retrieveable":true,"searchLayoutable":true,"searchable":true,"supportedScopes":[{"label":"All Accounts","name":"everything"},{"label":"My Accounts","name":"mine"}],"sobjectDescribeOption":"FULL","triggerable":true,"undeletable":true,"updateable":true,"urls":{"approvalLayouts":"/services/data/v63.0/sobjects/Account/describe/approvalLayouts","compactLayouts":"/services/data/v63.0/sobjects/Account/describe/compactLayouts","defaultValues":"/services/data/v63.0/sobjects/Account/defaultValues","describe":"/services/data/v63.0/sobjects/Account/describe","layouts":"/services/data/v63.0/sobjects/Account/describe/layouts","listviews":"/services/data/v63.0/sobjects/Account/listviews","quickActions":"/services/data/v63.0/sobjects/Account/quickActions","rowTemplate":"/services/data/v63.0/sobjects/Account/{ID}","sobject":"/services/data/v63.0/sobjects/Account"}}`

const goldenDescribeSystemFileSuccessV63 = `{"actionOverrides":[],"activateable":false,"associateEntityType":null,"associateParentEntity":null,"childRelationships":[],"compactLayoutable":true,"createable":false,"custom":false,"customSetting":false,"deletable":false,"deepCloneable":false,"deprecatedAndHidden":false,"feedEnabled":true,"fields":[{"aggregatable":true,"aiPredictionField":false,"autoNumber":false,"byteLength":18,"calculated":false,"calculatedFormula":null,"cascadeDelete":false,"caseSensitive":false,"compoundFieldName":null,"controllerName":null,"createable":false,"custom":false,"defaultValue":null,"defaultValueFormula":null,"defaultedOnCreate":false,"dependentPicklist":false,"deprecatedAndHidden":false,"digits":0,"displayLocationInDecimal":false,"encrypted":false,"externalId":false,"extraTypeInfo":null,"filterable":true,"filteredLookupInfo":null,"formulaTreatNullNumberAsZero":false,"groupable":true,"highScaleNumber":false,"htmlFormatted":false,"idLookup":true,"inlineHelpText":null,"label":"File ID","length":18,"mask":null,"maskType":null,"name":"Id","nameField":false,"namePointing":false,"nillable":true,"permissionable":true,"picklistValues":[],"polymorphicForeignKey":false,"precision":0,"queryByDistance":false,"readable":true,"referenceTargetField":null,"referenceTo":[],"relationshipName":null,"relationshipOrder":null,"restrictedDelete":false,"restrictedPicklist":false,"scale":0,"searchPrefilterable":true,"soapType":"xsd:string","sortable":true,"type":"id","unique":false,"updateable":false,"writeRequiresMasterRead":false}],"hasSubtypes":false,"isSubtype":false,"keyPrefix":"068","label":"File","labelPlural":"Files","layoutable":true,"listviewable":null,"lookupLayoutable":null,"mergeable":false,"mruEnabled":true,"name":"_System_File","namedLayoutInfos":[],"networkScopeFieldName":null,"queryable":true,"recordTypeInfos":[],"replicateable":true,"retrieveable":true,"searchLayoutable":true,"searchable":false,"supportedScopes":[{"label":"All Files","name":"everything"},{"label":"My Files","name":"mine"}],"sobjectDescribeOption":"FULL","triggerable":true,"undeletable":true,"updateable":false,"urls":{"approvalLayouts":"/services/data/v63.0/sobjects/_System_File/describe/approvalLayouts","compactLayouts":"/services/data/v63.0/sobjects/_System_File/describe/compactLayouts","defaultValues":"/services/data/v63.0/sobjects/_System_File/defaultValues","describe":"/services/data/v63.0/sobjects/_System_File/describe","layouts":"/services/data/v63.0/sobjects/_System_File/describe/layouts","listviews":"/services/data/v63.0/sobjects/_System_File/listviews","quickActions":"/services/data/v63.0/sobjects/_System_File/quickActions","rowTemplate":"/services/data/v63.0/sobjects/_System_File/{ID}","sobject":"/services/data/v63.0/sobjects/_System_File"}}`
