package permissions

import (
	"context"
	"encoding/json"
	"strings"
	"testing"

	cp "github.com/pingcap-inc/nexuscrm-contract/pkg/controlplane"
)

func TestPermissionSetDefinitionPreflightTrustsOnlyExactDeclaredCustomPermissionDependency(t *testing.T) {
	_, lifecycle, err := NewPermissionSetDefinitionManagedLifecycleRegistration()
	if err != nil {
		t.Fatal(err)
	}
	request := permissionSetDefinitionWithCustomPermissionDependencyForTest(t)
	lifecycleRequest := cp.NewComponentManagedItemLifecycleRequest(request)
	store := newPermissionSetDefinitionLifecycleMemoryStore()

	plan, err := lifecycle.Lifecycle().Plan(context.Background(), cp.ComponentManagedScopeItem, lifecycleRequest, store)
	if err != nil {
		t.Fatalf("declared dependency preflight failed: %v", err)
	}
	if _, err := lifecycle.Lifecycle().Project(
		context.Background(),
		cp.ComponentManagedScopeItem,
		lifecycleRequest,
		store,
	); err == nil || !strings.Contains(err.Error(), "custom permission SendRecordEmail does not exist") {
		t.Fatalf("fresh projection error = %v, want missing live dependency", err)
	}
	if _, err := lifecycle.Lifecycle().Mutate(
		context.Background(),
		cp.ComponentManagedScopeItem,
		lifecycleRequest,
		plan,
		store,
	); err == nil || !strings.Contains(err.Error(), "custom permission SendRecordEmail does not exist") {
		t.Fatalf("locked mutation error = %v, want missing live dependency", err)
	}

	store.rows["_System_CustomPermission"] = []cp.ComponentRow{{
		"Id":        "custom-send-record-email",
		"ApiName":   "SendRecordEmail",
		"IsActive":  false,
		"IsDeleted": true,
	}}
	inactivePlan, err := lifecycle.Lifecycle().Plan(
		context.Background(),
		cp.ComponentManagedScopeItem,
		lifecycleRequest,
		store,
	)
	if err != nil {
		t.Fatalf("declared inactive dependency preflight failed: %v", err)
	}
	if _, err := lifecycle.Lifecycle().Mutate(
		context.Background(),
		cp.ComponentManagedScopeItem,
		lifecycleRequest,
		inactivePlan,
		store,
	); err == nil || !strings.Contains(err.Error(), "not an active canonical catalog entry") {
		t.Fatalf("locked inactive dependency error = %v", err)
	}
	delete(store.rows, "_System_CustomPermission")
	store.rows["_System_CustomPermission"] = []cp.ComponentRow{{
		"Id":        "custom-send-record-email",
		"ApiName":   "sendrecordemail",
		"IsActive":  true,
		"IsDeleted": false,
	}}
	if _, err := lifecycle.Lifecycle().Plan(
		context.Background(),
		cp.ComponentManagedScopeItem,
		lifecycleRequest,
		store,
	); err == nil || !strings.Contains(err.Error(), "not an active canonical catalog entry") {
		t.Fatalf("declared noncanonical dependency preflight error = %v", err)
	}
	delete(store.rows, "_System_CustomPermission")

	for _, dependency := range []cp.ComponentReference{
		{},
		{Kind: customPermissionComponentKind, BusinessKey: "OtherPermission"},
		{Kind: customPermissionComponentKind, BusinessKey: "sendrecordemail"},
		{Kind: "invocable_action", BusinessKey: "SendRecordEmail"},
	} {
		withoutExact := request
		if dependency.Kind == "" {
			withoutExact.Component.DependsOn = nil
		} else {
			withoutExact.Component.DependsOn = []cp.ComponentReference{dependency}
		}
		if _, err := lifecycle.Lifecycle().Plan(
			context.Background(),
			cp.ComponentManagedScopeItem,
			cp.NewComponentManagedItemLifecycleRequest(withoutExact),
			store,
		); err == nil || !strings.Contains(err.Error(), "custom permission SendRecordEmail does not exist") {
			t.Fatalf("dependency %#v preflight error = %v", dependency, err)
		}
	}
}

func TestAssignmentPolicyPreflightTrustsOnlyExactDeclaredDefinitionDependency(t *testing.T) {
	lifecycle := assignmentPolicyTestLifecycleProvider()
	request := assignmentPolicyManagedRequestFor(
		t,
		"salesforce-crm-standard",
		"PingCAP_SDR_Send_Record_Email_SDR",
		"PingCAP_SDR_Send_Record_Email",
	)
	request.Component.DependsOn = []cp.ComponentReference{{
		Kind:        permissionSetDefinitionComponentKind,
		BusinessKey: "PingCAP_SDR_Send_Record_Email",
	}}
	lifecycleRequest := cp.NewComponentManagedItemLifecycleRequest(request)
	store := newPermissionSetDefinitionLifecycleMemoryStore()

	plan, err := lifecycle.Plan(context.Background(), cp.ComponentManagedScopeItem, lifecycleRequest, store)
	if err != nil {
		t.Fatalf("declared Definition dependency preflight failed: %v", err)
	}
	var planned assignmentPolicyPlan
	if err := json.Unmarshal(plan.OpaquePlan(), &planned); err != nil {
		t.Fatal(err)
	}
	if planned.TargetID != "" || planned.TargetOwnerPack != "" {
		t.Fatalf("declared dependency manufactured live identity: %#v", planned)
	}
	if _, err := lifecycle.Project(
		context.Background(),
		cp.ComponentManagedScopeItem,
		lifecycleRequest,
		store,
	); err == nil || !strings.Contains(err.Error(), "not one live Permission Set Definition") {
		t.Fatalf("fresh projection error = %v, want missing live Definition", err)
	}
	if _, err := lifecycle.Mutate(
		context.Background(),
		cp.ComponentManagedScopeItem,
		lifecycleRequest,
		plan,
		store,
	); err == nil || !strings.Contains(err.Error(), "root lock is incomplete") {
		t.Fatalf("locked mutation error = %v, want missing live Definition", err)
	}

	store.rows["PermissionSet"] = []cp.ComponentRow{{
		"Id":               "permission-set-sdr-email",
		"Name":             "PingCAP_SDR_Send_Record_Email",
		"OwnerPack":        "salesforce-crm-standard",
		"IsActive":         false,
		"IsDeleted":        true,
		"IsCustom":         true,
		"ProfileId":        nil,
		"IsOwnedByProfile": false,
	}}
	inactivePlan, err := lifecycle.Plan(
		context.Background(),
		cp.ComponentManagedScopeItem,
		lifecycleRequest,
		store,
	)
	if err != nil {
		t.Fatalf("declared inactive Definition preflight failed: %v", err)
	}
	if _, err := lifecycle.Mutate(
		context.Background(),
		cp.ComponentManagedScopeItem,
		lifecycleRequest,
		inactivePlan,
		store,
	); err == nil || !strings.Contains(err.Error(), "root lock is incomplete") {
		t.Fatalf("locked inactive Definition error = %v", err)
	}
	delete(store.rows, "PermissionSet")
	store.rows["PermissionSet"] = []cp.ComponentRow{{
		"Id":               "permission-set-sdr-email",
		"Name":             "PingCAP_SDR_Send_Record_Email",
		"OwnerPack":        "salesforce-crm-standard",
		"IsActive":         true,
		"IsDeleted":        false,
		"IsCustom":         false,
		"ProfileId":        nil,
		"IsOwnedByProfile": false,
	}}
	if _, err := lifecycle.Plan(
		context.Background(),
		cp.ComponentManagedScopeItem,
		lifecycleRequest,
		store,
	); err == nil || !strings.Contains(err.Error(), "not an active managed Definition") {
		t.Fatalf("declared noncanonical Definition preflight error = %v", err)
	}
	delete(store.rows, "PermissionSet")

	for _, dependency := range []cp.ComponentReference{
		{},
		{Kind: permissionSetDefinitionComponentKind, BusinessKey: "Other_Definition"},
		{Kind: permissionSetDefinitionComponentKind, BusinessKey: "pingcap_sdr_send_record_email"},
		{Kind: customPermissionComponentKind, BusinessKey: "PingCAP_SDR_Send_Record_Email"},
	} {
		withoutExact := request
		if dependency.Kind == "" {
			withoutExact.Component.DependsOn = nil
		} else {
			withoutExact.Component.DependsOn = []cp.ComponentReference{dependency}
		}
		if _, err := lifecycle.Plan(
			context.Background(),
			cp.ComponentManagedScopeItem,
			cp.NewComponentManagedItemLifecycleRequest(withoutExact),
			store,
		); err == nil || !strings.Contains(err.Error(), "not one live Permission Set Definition") {
			t.Fatalf("dependency %#v preflight error = %v", dependency, err)
		}
	}
}

func permissionSetDefinitionWithCustomPermissionDependencyForTest(t *testing.T) cp.ComponentManagedRequest {
	t.Helper()
	base, _, err := NewPermissionSetDefinitionManagedLifecycleRegistration()
	if err != nil {
		t.Fatal(err)
	}
	payload := []byte(`{
		"schema":"nexuscrm.permission-set-definition/v1",
		"label":"PingCAP SDR Send Record Email",
		"active":true,
		"systemPermissions":[],
		"customPermissions":["SendRecordEmail"],
		"objectPermissions":[],
		"fieldPermissions":[]
	}`)
	component := cp.ManifestComponent{
		Kind:          permissionSetDefinitionComponentKind,
		BusinessKey:   "PingCAP_SDR_Send_Record_Email",
		Manageability: cp.ManageabilityLocked,
		DependsOn: []cp.ComponentReference{{
			Kind:        customPermissionComponentKind,
			BusinessKey: "SendRecordEmail",
		}},
		Payload: append(json.RawMessage(nil), payload...),
	}
	build := &permissionSetDefinitionBuildContext{packName: "salesforce-crm-standard"}
	if err := base.BuildHandler(build, cp.ComponentBuildRequest{
		PackName:  build.packName,
		Component: component,
		Payload:   payload,
	}); err != nil {
		t.Fatal(err)
	}
	return cp.ComponentManagedRequest{
		PackName:           build.packName,
		Component:          component,
		Payload:            payload,
		ExpectedProjection: build.managed[0].ExpectedProjection,
	}
}
