package mapping

import (
	"context"
	"errors"
	"reflect"
	"strings"
	"testing"
	"time"

	commonsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/commonv1"
	semantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/permissionadminv1"
	runtimev1 "github.com/pingcap-inc/nexuscrm-contract/wire-go/gen/runtime/v1"
)

func TestPermissionAdministrationRejectsUnpublishedConflictFailure(t *testing.T) {
	wireError := ToPlatformStatusError(&commonsemantic.Failure{Category: commonsemantic.FailureConflict}, semantic.CapabilityName)
	var failure *commonsemantic.Failure
	if err := FromPlatformStatusError(wireError, semantic.CapabilityName); !errors.As(err, &failure) || failure.Category != commonsemantic.FailureInternal {
		t.Fatalf("unsupported permission-admin conflict decoded as %#v", err)
	}
}

func TestPermissionAdministrationSelectorMappingsAreComplete(t *testing.T) {
	for _, selector := range []semantic.ReadSelector{
		semantic.ReadSystemCatalog,
		semantic.ReadSystemGrants,
		semantic.ReadRecordTypeCatalog,
		semantic.ReadRecordTypeGrants,
		semantic.ReadCustomCatalog,
		semantic.ReadCustomGrants,
	} {
		wireSelector, ok := toWirePermissionAdministrationReadSelector(selector)
		if !ok {
			t.Fatalf("read selector %q has no wire value", selector)
		}
		decoded, ok := fromWirePermissionAdministrationReadSelector(wireSelector)
		if !ok || decoded != selector {
			t.Fatalf("read selector %q decoded as %q, ok=%t", selector, decoded, ok)
		}
	}
	for _, selector := range []semantic.MutationSelector{
		semantic.MutateSystemGrants,
		semantic.MutateRecordTypeGrants,
		semantic.MutateCustomGrants,
	} {
		wireSelector, ok := toWirePermissionAdministrationMutationSelector(selector)
		if !ok {
			t.Fatalf("mutation selector %q has no wire value", selector)
		}
		decoded, ok := fromWirePermissionAdministrationMutationSelector(wireSelector)
		if !ok || decoded != selector {
			t.Fatalf("mutation selector %q decoded as %q, ok=%t", selector, decoded, ok)
		}
	}
	if _, ok := fromWirePermissionAdministrationReadSelector(runtimev1.PermissionAdministrationReadSelector_PERMISSION_ADMINISTRATION_READ_SELECTOR_UNSPECIFIED); ok {
		t.Fatal("unspecified read selector mapped to semantic")
	}
	if _, ok := fromWirePermissionAdministrationMutationSelector(runtimev1.PermissionAdministrationMutationSelector_PERMISSION_ADMINISTRATION_MUTATION_SELECTOR_UNSPECIFIED); ok {
		t.Fatal("unspecified mutation selector mapped to semantic")
	}
}

func permissionAdminMappingContext(t *testing.T) context.Context {
	t.Helper()
	ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Second))
	t.Cleanup(cancel)
	return ctx
}

func permissionAdminMappingReceipts() semantic.Receipts {
	return semantic.Receipts{ProtocolVersion: "1.0", CapabilityVersion: semantic.CapabilityName, CatalogRevision: 7, SchemaGeneration: 2, EngineGeneration: 3, SecurityEpoch: 4}
}

func TestPermissionAdministrationReadRoundTrip(t *testing.T) {
	ctx := permissionAdminMappingContext(t)
	request := semantic.ReadRequest{Selector: semantic.ReadRecordTypeGrants, PermissionSetID: "ps-1"}
	wireRequest, err := ToWireReadPermissionAdministrationRequest(ctx, request)
	if err != nil {
		t.Fatalf("ToWireReadPermissionAdministrationRequest() error = %v", err)
	}
	decodedRequest, err := FromWireReadPermissionAdministrationRequest(ctx, wireRequest)
	if err != nil || !reflect.DeepEqual(decodedRequest, request) {
		t.Fatalf("decoded request = %#v, %v; want %#v", decodedRequest, err, request)
	}
	response := semantic.ReadResponse{RecordTypeGrants: []semantic.Grant{{PermissionID: "rt-1", Enabled: true}}, Receipts: permissionAdminMappingReceipts()}
	wireResponse, err := ToWireReadPermissionAdministrationResponse(request, response)
	if err != nil {
		t.Fatalf("ToWireReadPermissionAdministrationResponse() error = %v", err)
	}
	decodedResponse, err := FromWireReadPermissionAdministrationResponse(request, wireResponse)
	if err != nil || !reflect.DeepEqual(decodedResponse, response) {
		t.Fatalf("decoded response = %#v, %v; want %#v", decodedResponse, err, response)
	}
}

func TestPermissionAdministrationInboundPreflightRejectsCountsFamiliesAndRawBytes(t *testing.T) {
	ctx := permissionAdminMappingContext(t)
	oversizedCount := &runtimev1.MutatePermissionAdministrationRequest{
		Selector:        runtimev1.PermissionAdministrationMutationSelector_PERMISSION_ADMINISTRATION_MUTATION_SELECTOR_SYSTEM_GRANTS,
		PermissionSetId: "ps-1",
		// Nil members prove that the count limit wins before nested grant conversion.
		Grants: make([]*runtimev1.PermissionAdministrationGrant, semantic.MaxGrants+1),
	}
	_, err := FromWireMutatePermissionAdministrationRequest(ctx, oversizedCount)
	var failure *commonsemantic.Failure
	if !errors.As(err, &failure) || failure.Category != commonsemantic.FailureResourceExhausted ||
		failure.LimitKind != commonsemantic.LimitOperationCount || failure.Maximum != semantic.MaxGrants {
		t.Fatalf("oversized grant count = %#v, want operation-count limit %d", err, semantic.MaxGrants)
	}

	oversizedRaw := &runtimev1.MutatePermissionAdministrationRequest{
		Selector:        runtimev1.PermissionAdministrationMutationSelector_PERMISSION_ADMINISTRATION_MUTATION_SELECTOR_SYSTEM_GRANTS,
		PermissionSetId: "ps-1",
		Grants: []*runtimev1.PermissionAdministrationGrant{{
			PermissionId: strings.Repeat("p", semantic.MaxSemanticRequestBytes), Enabled: true,
		}},
	}
	_, err = FromWireMutatePermissionAdministrationRequest(ctx, oversizedRaw)
	if !errors.As(err, &failure) || failure.Category != commonsemantic.FailureResourceExhausted ||
		failure.LimitKind != commonsemantic.LimitSemanticRequest || failure.Maximum != semantic.MaxSemanticRequestBytes {
		t.Fatalf("oversized raw grant bytes = %#v, want semantic-request limit %d", err, semantic.MaxSemanticRequestBytes)
	}

	request := semantic.ReadRequest{Selector: semantic.ReadSystemCatalog}
	wrongFamily := &runtimev1.ReadPermissionAdministrationResponse{
		CustomCatalog: make([]*runtimev1.PermissionAdministrationCustomPermission, semantic.MaxCatalogEntries+1),
		Receipts:      toWireReceipts(permissionAdminMappingReceipts(), platformCapability(semantic.CapabilityName)),
	}
	if got, responseErr := FromWireReadPermissionAdministrationResponse(request, wrongFamily); responseErr == nil ||
		len(got.CustomCatalog) != 0 || len(got.SystemCatalog) != 0 {
		t.Fatalf("wrong-family response = %#v, %v; want rejection before semantic catalogs", got, responseErr)
	}
}

func TestPermissionAdministrationMutationRoundTrip(t *testing.T) {
	ctx := permissionAdminMappingContext(t)
	request := semantic.MutateRequest{Selector: semantic.MutateCustomGrants, PermissionSetID: "ps-1", Grants: []semantic.Grant{{PermissionID: "cp-1", Enabled: false}}}
	wireRequest, err := ToWireMutatePermissionAdministrationRequest(ctx, request)
	if err != nil {
		t.Fatalf("ToWireMutatePermissionAdministrationRequest() error = %v", err)
	}
	decodedRequest, err := FromWireMutatePermissionAdministrationRequest(ctx, wireRequest)
	if err != nil || !reflect.DeepEqual(decodedRequest, request) {
		t.Fatalf("decoded request = %#v, %v; want %#v", decodedRequest, err, request)
	}
	response := semantic.MutateResponse{Receipts: permissionAdminMappingReceipts()}
	wireResponse, err := ToWireMutatePermissionAdministrationResponse(request, response)
	if err != nil {
		t.Fatalf("ToWireMutatePermissionAdministrationResponse() error = %v", err)
	}
	decodedResponse, err := FromWireMutatePermissionAdministrationResponse(request, wireResponse)
	if err != nil || !reflect.DeepEqual(decodedResponse, response) {
		t.Fatalf("decoded response = %#v, %v; want %#v", decodedResponse, err, response)
	}
}
