package packs

import (
	"strings"
	"testing"
)

// TestConnectorFieldMappingKind_AppPackAccepted confirms that a connector_field_mapping
// component in an app-pack manifest does not produce an
// unsupported_for_category diagnostic.
func TestConnectorFieldMappingKind_AppPackAccepted(t *testing.T) {
	payload := `[
		{
			"sourceObject": "Contact",
			"targetObject": "Contact",
			"actionType":   "syncContact",
			"direction":    "inbound",
			"mappings": [
				{"sourceField": "email", "targetField": "Email"}
			]
		}
	]`

	root := writePackFixture(t, "my-app-pack", validPackManifest(`[
		{
			"kind":          "connector_field_mapping",
			"businessKey":   "jira-like-sample/contact-sync-inbound",
			"manageability": "locked",
			"payload":       `+jsonRawMessage(payload)+`
		}
	]`, ``))

	report := ValidateInstallablePackSourceWithOptions("local_path:"+root, testPackSourceOptions(t))
	for _, d := range report.Diagnostics {
		if d.Code == "manifest.component.unsupported_for_category" {
			t.Fatalf("connector_field_mapping should be allowed in app-pack but got: %s", d.String())
		}
	}
}

// TestConnectorFieldMappingKind_ConnectorPackRejected confirms that the new kind
// is rejected in a connector-pack manifest (RFC #1547 defers that widening).
func TestConnectorFieldMappingKind_ConnectorPackRejected(t *testing.T) {
	payload := `[
		{
			"sourceObject": "Contact",
			"targetObject": "Contact",
			"actionType":   "syncContact",
			"direction":    "inbound",
			"mappings": [
				{"sourceField": "email", "targetField": "Email"}
			]
		}
	]`

	root := writePackFixture(t, "test-connector", validConnectorPackManifest("test-connector", `[
		{
			"kind":          "connector_field_mapping",
			"businessKey":   "test-connector/contact-sync-inbound",
			"manageability": "locked",
			"payload":       `+jsonRawMessage(payload)+`
		}
	]`))

	report := ValidateInstallablePackSourceWithOptions("local_path:"+root, testPackSourceOptions(t))
	assertInstallableDiagnostic(t, report, "manifest.component.unsupported_for_category")
}

func TestConnectorFieldMappingValidatePackRejectsInvalidPayload(t *testing.T) {
	payload := `[
		{
			"sourceObject": "Contact",
			"targetObject": "Contact",
			"actionType":   "syncContact",
			"direction":    "sideways",
			"mappings": [
				{"sourceField": "email", "targetField": "Email"}
			]
		}
	]`

	root := writePackFixture(t, "my-app-pack", validPackManifest(`[
		{
			"kind":          "connector_field_mapping",
			"businessKey":   "jira-like-sample/contact-sync-inbound",
			"manageability": "locked",
			"payload":       `+jsonRawMessage(payload)+`
		}
	]`, ``))

	report := ValidateInstallablePackSourceWithOptions("local_path:"+root, testPackSourceOptions(t))
	assertInstallableDiagnostic(t, report, "component.payload.invalid_schema")
}

func TestConnectorFieldMappingValidatePackRejectsBusinessKeySourceMismatch(t *testing.T) {
	payload := `[
		{
			"sourceObject": "Contact",
			"targetObject": "Contact",
			"actionType":   "syncContact",
			"direction":    "inbound",
			"mappings": [
				{"sourceField": "email", "targetField": "Email"}
			]
		}
	]`

	root := writePackFixture(t, "my-app-pack", validPackManifest(`[
		{
			"kind":          "connector_field_mapping",
			"businessKey":   "other-pack/contact-sync-inbound",
			"manageability": "locked",
			"payload":       `+jsonRawMessage(payload)+`
		}
	]`, ``))

	report := ValidateInstallablePackSourceWithOptions("local_path:"+root, testPackSourceOptions(t))
	assertInstallableDiagnostic(t, report, "connector_field_mapping.business_key.mismatch_pack")
}

func TestConnectorFieldMappingValidatePackRejectsCrossComponentDuplicateCaseInsensitive(t *testing.T) {
	payloadA := `[
		{
			"sourceObject": "Contact",
			"targetObject": "Contact",
			"actionType":   "syncContact",
			"direction":    "inbound",
			"mappings": [
				{"sourceField": "Email", "targetField": "Email"}
			]
		}
	]`
	payloadB := `[
		{
			"sourceObject": "contact",
			"targetObject": "Contact",
			"actionType":   "syncContact",
			"direction":    "inbound",
			"mappings": [
				{"sourceField": "email", "targetField": "OtherEmail"}
			]
		}
	]`

	root := writePackFixture(t, "my-app-pack", validPackManifest(`[
		{
			"kind":          "connector_field_mapping",
			"businessKey":   "jira-like-sample/contact-sync-inbound-a",
			"manageability": "locked",
			"payload":       `+jsonRawMessage(payloadA)+`
		},
		{
			"kind":          "connector_field_mapping",
			"businessKey":   "jira-like-sample/contact-sync-inbound-b",
			"manageability": "locked",
			"payload":       `+jsonRawMessage(payloadB)+`
		}
	]`, ``))

	report := ValidateInstallablePackSourceWithOptions("local_path:"+root, testPackSourceOptions(t))
	assertInstallableDiagnostic(t, report, "component.plan.invalid")
	if !strings.Contains(report.Error(), "duplicate business key") {
		t.Fatalf("expected duplicate business key diagnostic, got:\n%s", report.Error())
	}
}

func TestConnectorFieldMappingValidatePackRejectsCrossComponentDuplicateTargetField(t *testing.T) {
	payloadA := `[
		{
			"sourceObject": "Contact",
			"targetObject": "Contact",
			"actionType":   "syncContact",
			"direction":    "inbound",
			"mappings": [
				{"sourceField": "email", "targetField": "Email"}
			]
		}
	]`
	payloadB := `[
		{
			"sourceObject": "Contact",
			"targetObject": "Contact",
			"actionType":   "syncContact",
			"direction":    "bidirectional",
			"mappings": [
				{"sourceField": "alternateEmail", "targetField": "Email"}
			]
		}
	]`

	root := writePackFixture(t, "my-app-pack", validPackManifest(`[
		{
			"kind":          "connector_field_mapping",
			"businessKey":   "jira-like-sample/contact-sync-inbound-a",
			"manageability": "locked",
			"payload":       `+jsonRawMessage(payloadA)+`
		},
		{
			"kind":          "connector_field_mapping",
			"businessKey":   "jira-like-sample/contact-sync-bidirectional-b",
			"manageability": "locked",
			"payload":       `+jsonRawMessage(payloadB)+`
		}
	]`, ``))

	report := ValidateInstallablePackSourceWithOptions("local_path:"+root, testPackSourceOptions(t))
	assertInstallableDiagnostic(t, report, "component.plan.invalid")
	if !strings.Contains(report.Error(), "duplicate effective target field") {
		t.Fatalf("expected duplicate effective target field diagnostic, got:\n%s", report.Error())
	}
}

// TestNewSourceBackedConnectorFieldMappingComponent_BusinessKeySourceMustMatchPack
// asserts the manifest businessKey first segment (the declared source/owner the
// rows install under) must equal packName — so a manifest cannot declare one
// source while the rows silently install under another. Mirrors the guard every
// other connector kind already enforces.
func TestNewSourceBackedConnectorFieldMappingComponent_BusinessKeySourceMustMatchPack(t *testing.T) {
	payload := []byte(`[{"sourceObject":"Contact","targetObject":"Contact","actionType":"syncContact","direction":"inbound","mappings":[{"sourceField":"email","targetField":"Email"}]}]`)

	// First segment != packName → rejected.
	mismatch := ManifestComponent{
		Kind:        ComponentKindConnectorFieldMapping,
		BusinessKey: "other-source/contact-sync-inbound",
		Payload:     payload,
	}
	if _, _, err := newSourceBackedConnectorFieldMappingComponent("my-app-pack", mismatch, payload); err == nil {
		t.Fatal("expected rejection: businessKey first segment must equal pack name")
	} else if !strings.Contains(err.Error(), "businessKey") {
		t.Errorf("expected error to mention businessKey, got: %v", err)
	}

	// First segment == packName → builds.
	match := ManifestComponent{
		Kind:        ComponentKindConnectorFieldMapping,
		BusinessKey: "my-app-pack/contact-sync-inbound",
		Payload:     payload,
	}
	if _, _, err := newSourceBackedConnectorFieldMappingComponent("my-app-pack", match, payload); err != nil {
		t.Fatalf("matching businessKey should build, got: %v", err)
	}
}
