package sfcrmappservice

import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"net/http"
	"net/url"
	"sort"
	"strconv"
	"strings"
	"time"

	crmwire "github.com/pingcap-inc/nexuscrm-app-packs/sfcrm/wire"
	catalogsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/catalog/consumerv1"
	commonsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/commonv1"
	permissionauthoringsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/permissionauthoringv1"
)

const (
	PermissionAuthoringCapabilityID = "io.nexuscrm.sfcrm.permission-authoring.v1"

	PermissionAuthoringSnapshotPath     = "/services/data/v63.0/permissions/authoring/snapshot"
	PermissionAuthoringFieldCatalogPath = "/services/data/v63.0/permissions/authoring/field-catalog"
	PermissionAuthoringSavePath         = "/services/data/v63.0/permissions/authoring/save"
	PermissionAuthoringStatusPath       = "/services/data/v63.0/permissions/authoring/status"

	// LegacyPermissionSetSystemGrantsPrefix remains only as an L2 deployment
	// compatibility envelope. Its implementation below delegates every write to
	// the Runtime aggregate; the removed dialect direct writer is not restored.
	LegacyPermissionSetSystemGrantsPrefix = "/services/data/v63.0/permissions/system/permissionset/"

	permissionAuthoringOutcomeUnknownCode = "PERMISSION_AUTHORING_OUTCOME_UNKNOWN"
	permissionAuthoringStaleCode          = "PERMISSION_AUTHORING_STALE_STATE"
	permissionAuthoringCommandMissingCode = "PERMISSION_AUTHORING_COMMAND_NOT_FOUND"
	permissionAuthoringAdmissionCode      = "PERMISSION_AUTHORING_ADMISSION_REJECTED"
)

type RuntimeReadPermissionAuthoringSnapshotFunc func(context.Context, string, permissionauthoringsemantic.SnapshotRequest) (permissionauthoringsemantic.SnapshotResponse, error)
type RuntimeSavePermissionAuthoringFunc func(context.Context, string, permissionauthoringsemantic.Request) (permissionauthoringsemantic.Response, error)
type RuntimeGetPermissionAuthoringStatusFunc func(context.Context, string, permissionauthoringsemantic.Request) (permissionauthoringsemantic.StatusResponse, error)

type RuntimePermissionAuthoringClient struct {
	readSnapshot RuntimeReadPermissionAuthoringSnapshotFunc
	save         RuntimeSavePermissionAuthoringFunc
	status       RuntimeGetPermissionAuthoringStatusFunc
}

func NewRuntimePermissionAuthoringClient(
	readSnapshot RuntimeReadPermissionAuthoringSnapshotFunc,
	save RuntimeSavePermissionAuthoringFunc,
	status RuntimeGetPermissionAuthoringStatusFunc,
) (*RuntimePermissionAuthoringClient, error) {
	if readSnapshot == nil || save == nil || status == nil {
		return nil, errors.New("sfcrm AppService: complete Runtime Permission Authoring lifecycle is required")
	}
	return &RuntimePermissionAuthoringClient{readSnapshot: readSnapshot, save: save, status: status}, nil
}

func (c *RuntimePermissionAuthoringClient) ReadSnapshot(ctx context.Context, bearer string, request permissionauthoringsemantic.SnapshotRequest) (permissionauthoringsemantic.SnapshotResponse, error) {
	if err := permissionauthoringsemantic.ValidateSnapshotRequest(ctx, request); err != nil {
		return permissionauthoringsemantic.SnapshotResponse{}, err
	}
	response, err := c.readSnapshot(ctx, bearer, request)
	if err != nil {
		return permissionauthoringsemantic.SnapshotResponse{}, normalizeRuntimeError(err)
	}
	if err := permissionauthoringsemantic.ValidateSnapshotResponse(request, response); err != nil {
		return permissionauthoringsemantic.SnapshotResponse{}, err
	}
	return response, nil
}

func (c *RuntimePermissionAuthoringClient) Save(ctx context.Context, bearer string, request permissionauthoringsemantic.Request) (permissionauthoringsemantic.Response, error) {
	if err := permissionauthoringsemantic.ValidateRequest(ctx, request); err != nil {
		return permissionauthoringsemantic.Response{}, err
	}
	response, err := c.save(ctx, bearer, request)
	if err != nil {
		return permissionauthoringsemantic.Response{}, normalizeRuntimeError(err)
	}
	if err := permissionauthoringsemantic.ValidateResponse(request, response); err != nil {
		return permissionauthoringsemantic.Response{}, err
	}
	return response, nil
}

func (c *RuntimePermissionAuthoringClient) Status(ctx context.Context, bearer string, request permissionauthoringsemantic.Request) (permissionauthoringsemantic.StatusResponse, error) {
	if err := permissionauthoringsemantic.ValidateRequest(ctx, request); err != nil {
		return permissionauthoringsemantic.StatusResponse{}, err
	}
	response, err := c.status(ctx, bearer, request)
	if err != nil {
		return permissionauthoringsemantic.StatusResponse{}, normalizeRuntimeError(err)
	}
	if err := permissionauthoringsemantic.ValidateStatusResponseForRequest(request, response); err != nil {
		return permissionauthoringsemantic.StatusResponse{}, err
	}
	return response, nil
}

type permissionAuthoringTargetDTO struct {
	Type string `json:"type"`
	ID   string `json:"id"`
}

type permissionAuthoringSnapshotRequestDTO struct {
	Target permissionAuthoringTargetDTO `json:"target"`
}

type permissionAuthoringFieldCatalogRequestDTO struct {
	Target             permissionAuthoringTargetDTO `json:"target"`
	ResourceType       string                       `json:"resourceType"`
	MinCatalogRevision string                       `json:"minCatalogRevision"`
}

type permissionAuthoringFieldCatalogFieldDTO struct {
	Name  string `json:"name"`
	Label string `json:"label"`
}

type permissionAuthoringFieldCatalogDTO struct {
	ResourceType    string                                    `json:"resourceType"`
	CatalogRevision string                                    `json:"catalogRevision"`
	Fields          []permissionAuthoringFieldCatalogFieldDTO `json:"fields"`
}

type permissionAuthoringCapabilityGrantDTO struct {
	CapabilityID string `json:"capabilityId"`
	Enabled      bool   `json:"enabled"`
}

type permissionAuthoringObjectGrantDTO struct {
	ResourceType string `json:"resourceType"`
	Read         bool   `json:"read"`
	Create       bool   `json:"create"`
	Edit         bool   `json:"edit"`
	Delete       bool   `json:"delete"`
	ViewAll      bool   `json:"viewAll"`
	ModifyAll    bool   `json:"modifyAll"`
}

type permissionAuthoringFieldGrantDTO struct {
	ResourceType string `json:"resourceType"`
	FieldName    string `json:"fieldName"`
	Read         bool   `json:"read"`
	Edit         bool   `json:"edit"`
}

type permissionAuthoringRecordTypeGrantDTO struct {
	RecordTypeID string `json:"recordTypeId"`
	ResourceType string `json:"resourceType,omitempty"`
	Visible      bool   `json:"visible"`
}

// permissionAuthoringChangesDTO is an input patch: omitted families mean no
// change. Snapshot output deliberately uses the total grants DTO below.
type permissionAuthoringChangesDTO struct {
	System      []permissionAuthoringCapabilityGrantDTO `json:"system,omitempty"`
	Objects     []permissionAuthoringObjectGrantDTO     `json:"objects,omitempty"`
	Fields      []permissionAuthoringFieldGrantDTO      `json:"fields,omitempty"`
	RecordTypes []permissionAuthoringRecordTypeGrantDTO `json:"recordTypes,omitempty"`
	Custom      []permissionAuthoringCapabilityGrantDTO `json:"custom,omitempty"`
}

type permissionAuthoringGrantsDTO struct {
	System      []permissionAuthoringCapabilityGrantDTO `json:"system"`
	Objects     []permissionAuthoringObjectGrantDTO     `json:"objects"`
	Fields      []permissionAuthoringFieldGrantDTO      `json:"fields"`
	RecordTypes []permissionAuthoringRecordTypeGrantDTO `json:"recordTypes"`
	Custom      []permissionAuthoringCapabilityGrantDTO `json:"custom"`
}

type permissionAuthoringCommandDTO struct {
	CommandID              string                        `json:"commandId"`
	Target                 permissionAuthoringTargetDTO  `json:"target"`
	ExpectedAuthoringToken string                        `json:"expectedAuthoringToken"`
	MinCatalogRevision     string                        `json:"minCatalogRevision"`
	Changes                permissionAuthoringChangesDTO `json:"changes"`
}

type permissionAuthoringStatusRequestDTO struct {
	Command permissionAuthoringCommandDTO `json:"command"`
}

type legacyPermissionSetSystemGrantsDTO struct {
	Grants map[string]bool `json:"grants"`
}

type permissionAuthoringSystemCatalogDTO struct {
	PermissionID         string `json:"permissionId"`
	Label                string `json:"label"`
	Category             string `json:"category"`
	Description          string `json:"description,omitempty"`
	RequiresPermissionID string `json:"requiresPermissionId,omitempty"`
}

type permissionAuthoringRecordTypeCatalogDTO struct {
	RecordTypeID string `json:"recordTypeId"`
	ResourceType string `json:"resourceType"`
	StableName   string `json:"stableName"`
	Label        string `json:"label"`
	Active       bool   `json:"active"`
}

type permissionAuthoringCustomCatalogDTO struct {
	PermissionID string `json:"permissionId"`
	StableName   string `json:"stableName"`
	Label        string `json:"label"`
}

type permissionAuthoringObjectCatalogDTO struct {
	ResourceType        string `json:"resourceType"`
	Label               string `json:"label"`
	SharingModel        string `json:"sharingModel,omitempty"`
	SharingParentObject string `json:"sharingParentObject,omitempty"`
}

type permissionAuthoringSnapshotDTO struct {
	CanonicalPermissionSetID string `json:"canonicalPermissionSetId"`
	AuthoringToken           string `json:"authoringToken"`
	CatalogRevision          string `json:"catalogRevision"`
	Catalog                  struct {
		Objects     []permissionAuthoringObjectCatalogDTO     `json:"objects"`
		System      []permissionAuthoringSystemCatalogDTO     `json:"system"`
		RecordTypes []permissionAuthoringRecordTypeCatalogDTO `json:"recordTypes"`
		Custom      []permissionAuthoringCustomCatalogDTO     `json:"custom"`
	} `json:"catalog"`
	Grants permissionAuthoringGrantsDTO `json:"grants"`
}

type permissionAuthoringResultDTO struct {
	CommandID                string `json:"commandId"`
	Outcome                  string `json:"outcome"`
	RejectionCode            string `json:"rejectionCode,omitempty"`
	CanonicalPermissionSetID string `json:"canonicalPermissionSetId,omitempty"`
	AuthoringToken           string `json:"authoringToken,omitempty"`
	CatalogRevision          string `json:"catalogRevision"`
	OutcomeExpiresAtUTC      string `json:"outcomeExpiresAtUtc"`
}

type permissionAuthoringStatusDTO struct {
	CommandID string                        `json:"commandId"`
	State     string                        `json:"state"`
	Result    *permissionAuthoringResultDTO `json:"result,omitempty"`
}

func permissionAuthoringTarget(value permissionAuthoringTargetDTO) (permissionauthoringsemantic.Target, bool) {
	kind := permissionauthoringsemantic.TargetKind("")
	switch value.Type {
	case "profile":
		kind = permissionauthoringsemantic.TargetProfile
	case "permissionSet":
		kind = permissionauthoringsemantic.TargetPermissionSet
	default:
		return permissionauthoringsemantic.Target{}, false
	}
	return permissionauthoringsemantic.Target{Kind: kind, ID: value.ID}, true
}

func permissionAuthoringCommand(value permissionAuthoringCommandDTO) (permissionauthoringsemantic.Request, bool) {
	target, ok := permissionAuthoringTarget(value.Target)
	revision, revisionErr := strconv.ParseUint(value.MinCatalogRevision, 10, 64)
	if !ok || revisionErr != nil || revision == 0 {
		return permissionauthoringsemantic.Request{}, false
	}
	request := permissionauthoringsemantic.Request{
		CommandID: value.CommandID, Target: target,
		ExpectedAuthoringToken: value.ExpectedAuthoringToken,
		MinCatalogRevision:     &revision,
	}
	for _, grant := range value.Changes.System {
		request.Changes.System = append(request.Changes.System, permissionauthoringsemantic.CapabilityGrantChange{CapabilityID: grant.CapabilityID, Enabled: grant.Enabled})
	}
	for _, grant := range value.Changes.Objects {
		request.Changes.Objects = append(request.Changes.Objects, permissionauthoringsemantic.ObjectGrantChange{ResourceType: grant.ResourceType, Read: grant.Read, Create: grant.Create, Edit: grant.Edit, Delete: grant.Delete, ViewAll: grant.ViewAll, ModifyAll: grant.ModifyAll})
	}
	for _, grant := range value.Changes.Fields {
		request.Changes.Fields = append(request.Changes.Fields, permissionauthoringsemantic.FieldGrantChange{ResourceType: grant.ResourceType, FieldName: grant.FieldName, Read: grant.Read, Edit: grant.Edit})
	}
	for _, grant := range value.Changes.RecordTypes {
		request.Changes.RecordTypes = append(request.Changes.RecordTypes, permissionauthoringsemantic.RecordTypeGrantChange{RecordTypeID: grant.RecordTypeID, ResourceType: grant.ResourceType, Visible: grant.Visible})
	}
	for _, grant := range value.Changes.Custom {
		request.Changes.Custom = append(request.Changes.Custom, permissionauthoringsemantic.CapabilityGrantChange{CapabilityID: grant.CapabilityID, Enabled: grant.Enabled})
	}
	return request, true
}

func projectPermissionAuthoringSnapshot(response permissionauthoringsemantic.SnapshotResponse) permissionAuthoringSnapshotDTO {
	result := permissionAuthoringSnapshotDTO{
		CanonicalPermissionSetID: response.CanonicalPermissionSetID,
		AuthoringToken:           response.AuthoringToken,
		CatalogRevision:          strconv.FormatUint(response.Receipts.CatalogRevision, 10),
		Grants: permissionAuthoringGrantsDTO{
			System: []permissionAuthoringCapabilityGrantDTO{}, Objects: []permissionAuthoringObjectGrantDTO{},
			Fields: []permissionAuthoringFieldGrantDTO{}, RecordTypes: []permissionAuthoringRecordTypeGrantDTO{},
			Custom: []permissionAuthoringCapabilityGrantDTO{},
		},
	}
	result.Catalog.System = []permissionAuthoringSystemCatalogDTO{}
	result.Catalog.Objects = []permissionAuthoringObjectCatalogDTO{}
	result.Catalog.RecordTypes = []permissionAuthoringRecordTypeCatalogDTO{}
	result.Catalog.Custom = []permissionAuthoringCustomCatalogDTO{}
	for _, value := range response.Catalog.System {
		result.Catalog.System = append(result.Catalog.System, permissionAuthoringSystemCatalogDTO{PermissionID: value.PermissionID, Label: value.Label, Category: value.Category, Description: value.Description, RequiresPermissionID: value.RequiresPermissionID})
	}
	for _, value := range response.Catalog.RecordTypes {
		result.Catalog.RecordTypes = append(result.Catalog.RecordTypes, permissionAuthoringRecordTypeCatalogDTO{RecordTypeID: value.RecordTypeID, ResourceType: value.ResourceType, StableName: value.StableName, Label: value.Label, Active: value.Active})
	}
	for _, value := range response.Catalog.Custom {
		result.Catalog.Custom = append(result.Catalog.Custom, permissionAuthoringCustomCatalogDTO{PermissionID: value.PermissionID, StableName: value.StableName, Label: value.Label})
	}
	for _, value := range response.Grants.System {
		result.Grants.System = append(result.Grants.System, permissionAuthoringCapabilityGrantDTO{CapabilityID: value.CapabilityID, Enabled: value.Enabled})
	}
	for _, value := range response.Grants.Objects {
		result.Grants.Objects = append(result.Grants.Objects, permissionAuthoringObjectGrantDTO{ResourceType: value.ResourceType, Read: value.Read, Create: value.Create, Edit: value.Edit, Delete: value.Delete, ViewAll: value.ViewAll, ModifyAll: value.ModifyAll})
	}
	for _, value := range response.Grants.Fields {
		result.Grants.Fields = append(result.Grants.Fields, permissionAuthoringFieldGrantDTO{ResourceType: value.ResourceType, FieldName: value.FieldName, Read: value.Read, Edit: value.Edit})
	}
	for _, value := range response.Grants.RecordTypes {
		result.Grants.RecordTypes = append(result.Grants.RecordTypes, permissionAuthoringRecordTypeGrantDTO{RecordTypeID: value.RecordTypeID, Visible: value.Visible})
	}
	for _, value := range response.Grants.Custom {
		result.Grants.Custom = append(result.Grants.Custom, permissionAuthoringCapabilityGrantDTO{CapabilityID: value.CapabilityID, Enabled: value.Enabled})
	}
	return result
}

func (s *Service) readPermissionAuthoringCatalogSpecs(
	ctx context.Context,
	minimum uint64,
) (catalogsemantic.AppMetadataViewV3, map[string]searchObjectSpec, error) {
	if s.appMetadataV3 == nil {
		return catalogsemantic.AppMetadataViewV3{}, nil, &commonsemantic.Failure{Category: commonsemantic.FailureUnavailable}
	}
	view, err := s.appMetadataV3(ctx, catalogsemantic.GetRequest{MinCatalogRevision: &minimum})
	if err != nil {
		return catalogsemantic.AppMetadataViewV3{}, nil, err
	}
	if err := catalogsemantic.ValidateAppMetadataViewV3(view); err != nil || view.AppID != AppID {
		return catalogsemantic.AppMetadataViewV3{}, nil, &commonsemantic.Failure{Category: commonsemantic.FailureUnavailable}
	}
	if view.Receipts.CatalogRevision < minimum {
		return catalogsemantic.AppMetadataViewV3{}, nil, &commonsemantic.Failure{
			Category: commonsemantic.FailureStaleState, StaleAxis: commonsemantic.StaleAxisCatalog,
			RequiredRevision: minimum, ServedRevision: view.Receipts.CatalogRevision,
		}
	}
	specs, err := searchObjectSpecsFromView(view)
	if err != nil {
		return catalogsemantic.AppMetadataViewV3{}, nil, err
	}
	return view, specs, nil
}

func projectPermissionAuthoringObjectCatalog(
	result *permissionAuthoringSnapshotDTO,
	view catalogsemantic.AppMetadataViewV3,
	specs map[string]searchObjectSpec,
) error {
	resourceTypes, err := permissionResourceTypes(specs)
	if err != nil {
		return err
	}
	for _, resourceType := range resourceTypes {
		spec := specs[strings.ToLower(resourceType)]
		result.Catalog.Objects = append(result.Catalog.Objects, permissionAuthoringObjectCatalogDTO{
			ResourceType: spec.APIName, Label: spec.Label, SharingModel: spec.SharingModel,
			SharingParentObject: spec.SharingParentObject,
		})
	}
	// The L1 response may assemble Catalog shape newer than the permission-state
	// Snapshot. Return that higher minimum so every subsequent field read and Save
	// is fenced at least to the exact shape shown to the administrator.
	result.CatalogRevision = strconv.FormatUint(view.Receipts.CatalogRevision, 10)
	return nil
}

func (s *Service) readPermissionAuthoringFieldCatalog(
	ctx context.Context,
	bearer string,
	target permissionauthoringsemantic.Target,
	resourceType string,
	minimumCatalogRevision uint64,
) (permissionAuthoringFieldCatalogDTO, error) {
	// Runtime Snapshot is the existing Permission Authoring admission owner. A
	// successful read proves this bearer may author the selected target without
	// incorrectly coupling that authority to the bearer's own field access.
	snapshot, err := s.permissionAuthoring.ReadSnapshot(ctx, bearer, permissionauthoringsemantic.SnapshotRequest{
		Target: target, MinCatalogRevision: &minimumCatalogRevision,
	})
	if err != nil {
		return permissionAuthoringFieldCatalogDTO{}, err
	}
	minimum := snapshot.Receipts.CatalogRevision
	view, specs, err := s.readPermissionAuthoringCatalogSpecs(ctx, minimum)
	if err != nil {
		return permissionAuthoringFieldCatalogDTO{}, err
	}
	spec, found := specs[strings.ToLower(resourceType)]
	if !found {
		return permissionAuthoringFieldCatalogDTO{}, &commonsemantic.Failure{Category: commonsemantic.FailureMissing}
	}
	if !describeAuthorityIsCurrent(spec) {
		return permissionAuthoringFieldCatalogDTO{}, &commonsemantic.Failure{Category: commonsemantic.FailureUnavailable}
	}
	result := permissionAuthoringFieldCatalogDTO{
		ResourceType:    spec.APIName,
		CatalogRevision: strconv.FormatUint(view.Receipts.CatalogRevision, 10),
		Fields:          make([]permissionAuthoringFieldCatalogFieldDTO, 0, len(spec.Fields)),
	}
	for _, field := range spec.Fields {
		result.Fields = append(result.Fields, permissionAuthoringFieldCatalogFieldDTO{
			Name: field.APIName, Label: field.Label,
		})
	}
	return result, nil
}

func projectPermissionAuthoringResult(response permissionauthoringsemantic.Response) permissionAuthoringResultDTO {
	return permissionAuthoringResultDTO{
		CommandID: response.CommandID, Outcome: string(response.Outcome), RejectionCode: string(response.RejectionCode),
		CanonicalPermissionSetID: response.CanonicalPermissionSetID, AuthoringToken: response.AuthoringToken,
		CatalogRevision: strconv.FormatUint(response.Receipts.CatalogRevision, 10), OutcomeExpiresAtUTC: response.OutcomeExpiresAtUTC,
	}
}

func projectPermissionAuthoringStatus(response permissionauthoringsemantic.StatusResponse) permissionAuthoringStatusDTO {
	result := permissionAuthoringStatusDTO{CommandID: response.CommandID, State: string(response.State)}
	if response.Result != nil {
		projected := projectPermissionAuthoringResult(*response.Result)
		result.Result = &projected
	}
	return result
}

func legacyPermissionSetSystemGrantsTarget(path string) (string, bool) {
	if !strings.HasPrefix(path, LegacyPermissionSetSystemGrantsPrefix) {
		return "", false
	}
	raw := strings.TrimPrefix(path, LegacyPermissionSetSystemGrantsPrefix)
	if raw == "" || strings.Contains(raw, "/") {
		return "", false
	}
	permissionSetID, err := url.PathUnescape(raw)
	if err != nil || permissionSetID == "" || strings.Contains(permissionSetID, "/") {
		return "", false
	}
	return permissionSetID, true
}

func legacyPermissionAuthoringCommandID(permissionSetID, authoringToken string, changes []permissionauthoringsemantic.CapabilityGrantChange) string {
	digest := sha256.New()
	_, _ = digest.Write([]byte("nexuscrm.sfcrm.legacy-system-permission.v1\x00"))
	_, _ = digest.Write([]byte(permissionSetID))
	_, _ = digest.Write([]byte{'\x00'})
	_, _ = digest.Write([]byte(authoringToken))
	for _, change := range changes {
		_, _ = digest.Write([]byte{'\x00'})
		_, _ = digest.Write([]byte(change.CapabilityID))
		if change.Enabled {
			_, _ = digest.Write([]byte("\x001"))
		} else {
			_, _ = digest.Write([]byte("\x000"))
		}
	}
	return "permission-authoring:legacy-system:" + hex.EncodeToString(digest.Sum(nil))
}

func permissionAuthoringFailureIs(err error, category commonsemantic.FailureCategory) bool {
	var failure *commonsemantic.Failure
	return errors.As(err, &failure) && failure.Category == category
}

func permissionAuthoringOutcomeAmbiguous(err error) bool {
	var failure *commonsemantic.Failure
	if !errors.As(err, &failure) {
		return true
	}
	switch failure.Category {
	case commonsemantic.FailureCanceled, commonsemantic.FailureDeadlineExceeded,
		commonsemantic.FailureIncompatible, commonsemantic.FailureUnavailable, commonsemantic.FailureInternal:
		return true
	case commonsemantic.FailureResourceExhausted:
		// Only the fail-fast admission limit is positive proof that Runtime
		// rejected the command before handler acceptance. Every other resource
		// limit may be observed after durable acceptance.
		return failure.LimitKind != commonsemantic.LimitAdmission
	default:
		return false
	}
}

// permissionAuthoringReservedAttempt keeps every Runtime call under the owning
// HTTP request cancellation while reserving half of the remaining deadline for
// Status/replay. A Save attempt may expire without consuming the parent context.
func permissionAuthoringReservedAttempt(ctx context.Context) (context.Context, context.CancelFunc) {
	deadline, ok := ctx.Deadline()
	if !ok {
		return context.WithCancel(ctx)
	}
	remaining := time.Until(deadline)
	if remaining <= 0 {
		return context.WithCancel(ctx)
	}
	budget := remaining / 2
	if budget <= 0 {
		budget = remaining
	}
	return context.WithTimeout(ctx, budget)
}

// savePermissionAuthoringWithReconciliation is the only write coordinator.
// It captures the admitted HTTP bearer once, so Save, Status, and the one
// missing-command replay cannot cross into a replacement browser principal.
// Every attempt uses the complete immutable request and exact CommandID.
func (s *Service) savePermissionAuthoringWithReconciliation(ctx context.Context, bearer string, command permissionauthoringsemantic.Request) (permissionauthoringsemantic.Response, error) {
	saveCtx, cancelSave := permissionAuthoringReservedAttempt(ctx)
	response, err := s.permissionAuthoring.Save(saveCtx, bearer, command)
	cancelSave()
	if err == nil || !permissionAuthoringOutcomeAmbiguous(err) {
		return response, err
	}
	statusCtx, cancelStatus := permissionAuthoringReservedAttempt(ctx)
	status, statusErr := s.permissionAuthoring.Status(statusCtx, bearer, command)
	cancelStatus()
	if statusErr == nil {
		if status.State == permissionauthoringsemantic.CommandCompleted && status.Result != nil {
			return *status.Result, nil
		}
		return permissionauthoringsemantic.Response{}, err
	}
	if permissionAuthoringFailureIs(statusErr, commonsemantic.FailureMissing) {
		replayCtx, cancelReplay := context.WithCancel(ctx)
		defer cancelReplay()
		replay, replayErr := s.permissionAuthoring.Save(replayCtx, bearer, command)
		if replayErr == nil && (replay.Outcome == permissionauthoringsemantic.OutcomeApplied || replay.Outcome == permissionauthoringsemantic.OutcomeNoop) {
			return replay, nil
		}
		// A later replay rejection cannot prove that the original ambiguous
		// Save was not accepted. Preserve the original unknown outcome.
		return permissionauthoringsemantic.Response{}, err
	}
	return permissionauthoringsemantic.Response{}, err
}

// permissionAuthoringStatusWithReplay turns Status into the recovery half of
// the command protocol. Runtime persists acceptance before it executes the
// aggregate transaction, while the journal intentionally stores only the
// request digest. An ACCEPTED command therefore cannot make progress unless a
// caller that still holds the complete immutable request replays Save. The
// Status HTTP request carries that request, and this AppService boundary keeps
// the replay under the same authenticated bearer that was just allowed to
// observe the command.
func (s *Service) permissionAuthoringStatusWithReplay(ctx context.Context, bearer string, command permissionauthoringsemantic.Request) (permissionauthoringsemantic.StatusResponse, error) {
	statusCtx, cancelStatus := permissionAuthoringReservedAttempt(ctx)
	status, err := s.permissionAuthoring.Status(statusCtx, bearer, command)
	cancelStatus()
	if err != nil || status.State != permissionauthoringsemantic.CommandAccepted {
		return status, err
	}

	replayCtx, cancelReplay := permissionAuthoringReservedAttempt(ctx)
	result, replayErr := s.permissionAuthoring.Save(replayCtx, bearer, command)
	cancelReplay()
	if replayErr == nil {
		return permissionauthoringsemantic.StatusResponse{
			CommandID: result.CommandID, CommandDigest: result.CommandDigest,
			State: permissionauthoringsemantic.CommandCompleted, Result: &result,
		}, nil
	}

	// Once Runtime has reported ACCEPTED, a replay-side error cannot prove that
	// the command disappeared or failed. Re-read the same journal once; if that
	// read is unavailable, preserve the already authenticated ACCEPTED
	// observation so the exact command remains recoverable.
	refreshCtx, cancelRefresh := permissionAuthoringReservedAttempt(ctx)
	refreshed, statusErr := s.permissionAuthoring.Status(refreshCtx, bearer, command)
	cancelRefresh()
	if statusErr == nil {
		return refreshed, nil
	}
	return status, nil
}

func (s *Service) serveLegacyPermissionSetSystemGrants(writer http.ResponseWriter, ctx context.Context, bearer, permissionSetID string, decoder *json.Decoder) {
	var body legacyPermissionSetSystemGrantsDTO
	if decoder.Decode(&body) != nil || requireJSONEOF(decoder) != nil {
		s.rejectPermissionAuthoring(writer, "Invalid request body")
		return
	}
	target := permissionauthoringsemantic.Target{Kind: permissionauthoringsemantic.TargetPermissionSet, ID: permissionSetID}
	snapshot, err := s.permissionAuthoring.ReadSnapshot(ctx, bearer, permissionauthoringsemantic.SnapshotRequest{Target: target})
	if err != nil {
		s.failures.Add(1)
		writePermissionAuthoringFailure(writer, err, false, false)
		return
	}
	catalog := make(map[string]struct{}, len(snapshot.Catalog.System))
	for _, permission := range snapshot.Catalog.System {
		catalog[permission.PermissionID] = struct{}{}
	}
	current := make(map[string]bool, len(snapshot.Grants.System))
	for _, grant := range snapshot.Grants.System {
		current[grant.CapabilityID] = grant.Enabled
	}
	capabilityIDs := make([]string, 0, len(body.Grants))
	for capabilityID := range body.Grants {
		if _, ok := catalog[capabilityID]; !ok {
			s.rejectPermissionAuthoring(writer, "Invalid system permission")
			return
		}
		capabilityIDs = append(capabilityIDs, capabilityID)
	}
	sort.Strings(capabilityIDs)
	changes := make([]permissionauthoringsemantic.CapabilityGrantChange, 0, len(capabilityIDs))
	for _, capabilityID := range capabilityIDs {
		enabled := body.Grants[capabilityID]
		if current[capabilityID] != enabled {
			changes = append(changes, permissionauthoringsemantic.CapabilityGrantChange{CapabilityID: capabilityID, Enabled: enabled})
		}
	}
	if len(changes) == 0 {
		s.successes.Add(1)
		writeLegacyJSON(writer, http.StatusOK, map[string]any{"success": true})
		return
	}
	revision := snapshot.Receipts.CatalogRevision
	command := permissionauthoringsemantic.Request{
		CommandID: legacyPermissionAuthoringCommandID(permissionSetID, snapshot.AuthoringToken, changes),
		Target:    target, ExpectedAuthoringToken: snapshot.AuthoringToken,
		MinCatalogRevision: &revision,
		Changes:            permissionauthoringsemantic.Changes{System: changes},
	}
	result, err := s.savePermissionAuthoringWithReconciliation(ctx, bearer, command)
	if err != nil {
		s.failures.Add(1)
		writePermissionAuthoringFailure(writer, err, true, false)
		return
	}
	if result.Outcome == permissionauthoringsemantic.OutcomeApplied || result.Outcome == permissionauthoringsemantic.OutcomeNoop {
		s.successes.Add(1)
		writeLegacyJSON(writer, http.StatusOK, map[string]any{"success": true})
		return
	}
	s.failures.Add(1)
	switch result.RejectionCode {
	case permissionauthoringsemantic.RejectionDenied:
		writeCRMErrorWith(writer, http.StatusForbidden, crmwire.SFCodeForbidden, "Insufficient access", writeLegacyJSON)
	case permissionauthoringsemantic.RejectionMissing:
		writeCRMErrorWith(writer, http.StatusNotFound, crmwire.SFCodeNotFound, "Record not found", writeLegacyJSON)
	case permissionauthoringsemantic.RejectionStaleAuthoringState, permissionauthoringsemantic.RejectionConflict:
		writeCRMErrorWith(writer, http.StatusConflict, permissionAuthoringStaleCode, "Permission state must be refreshed", writeLegacyJSON)
	default:
		writeCRMErrorWith(writer, http.StatusBadRequest, crmwire.SFCodeInvalidRequest, "Invalid permission change", writeLegacyJSON)
	}
}

func (s *Service) servePermissionAuthoring(writer http.ResponseWriter, request *http.Request) bool {
	legacyPermissionSetID, legacy := legacyPermissionSetSystemGrantsTarget(request.URL.Path)
	if request.URL.Path != PermissionAuthoringSnapshotPath && request.URL.Path != PermissionAuthoringFieldCatalogPath && request.URL.Path != PermissionAuthoringSavePath && request.URL.Path != PermissionAuthoringStatusPath && !legacy {
		return false
	}
	expectedMethod := http.MethodPost
	if legacy {
		expectedMethod = http.MethodPatch
	}
	if request.Method != expectedMethod {
		writer.Header().Set("Allow", expectedMethod)
		writeCRMErrorWith(writer, http.StatusMethodNotAllowed, crmwire.SFCodeInvalidRequest, "Method not allowed", writeLegacyJSON)
		return true
	}
	s.requests.Add(1)
	if s.draining.Load() {
		s.drainRejected.Add(1)
		s.failures.Add(1)
		writeCRMErrorWith(writer, http.StatusServiceUnavailable, crmwire.SFCodeUnknownException, "Service is draining", writeLegacyJSON)
		return true
	}
	bearer, ok := endUserBearer(request.Header.Values("Authorization"))
	if !ok {
		s.localRejected.Add(1)
		s.failures.Add(1)
		writeCRMErrorWith(writer, http.StatusUnauthorized, crmwire.SFCodeInvalidSessionID, "Session expired or invalid", writeLegacyJSON)
		return true
	}
	s.inFlight.Add(1)
	defer s.inFlight.Add(-1)
	ctx, cancel := context.WithTimeout(request.Context(), s.requestTimeout)
	defer cancel()
	request.Body = http.MaxBytesReader(writer, request.Body, s.maxRequestBytes)
	decoder := json.NewDecoder(request.Body)
	if legacy {
		s.serveLegacyPermissionSetSystemGrants(writer, ctx, bearer, legacyPermissionSetID, decoder)
		return true
	}

	switch request.URL.Path {
	case PermissionAuthoringSnapshotPath:
		var body permissionAuthoringSnapshotRequestDTO
		if decoder.Decode(&body) != nil || requireJSONEOF(decoder) != nil {
			s.rejectPermissionAuthoring(writer, "Invalid request body")
			return true
		}
		target, valid := permissionAuthoringTarget(body.Target)
		if !valid {
			s.rejectPermissionAuthoring(writer, "Invalid permission target")
			return true
		}
		response, err := s.permissionAuthoring.ReadSnapshot(ctx, bearer, permissionauthoringsemantic.SnapshotRequest{Target: target})
		if err != nil {
			s.failures.Add(1)
			writePermissionAuthoringFailure(writer, err, false, false)
			return true
		}
		view, specs, err := s.readPermissionAuthoringCatalogSpecs(ctx, response.Receipts.CatalogRevision)
		if err != nil {
			s.failures.Add(1)
			writePermissionAuthoringFailure(writer, err, false, false)
			return true
		}
		projected := projectPermissionAuthoringSnapshot(response)
		if err := projectPermissionAuthoringObjectCatalog(&projected, view, specs); err != nil {
			s.failures.Add(1)
			writePermissionAuthoringFailure(writer, err, false, false)
			return true
		}
		s.successes.Add(1)
		writeLegacyJSON(writer, http.StatusOK, projected)
	case PermissionAuthoringFieldCatalogPath:
		var body permissionAuthoringFieldCatalogRequestDTO
		if decoder.Decode(&body) != nil || requireJSONEOF(decoder) != nil {
			s.rejectPermissionAuthoring(writer, "Invalid request body")
			return true
		}
		target, valid := permissionAuthoringTarget(body.Target)
		minimum, revisionErr := strconv.ParseUint(body.MinCatalogRevision, 10, 64)
		if !valid || !commonsemantic.ValidObjectIdentifier(body.ResourceType) ||
			minimum == 0 || revisionErr != nil {
			s.rejectPermissionAuthoring(writer, "Invalid field catalog request")
			return true
		}
		response, err := s.readPermissionAuthoringFieldCatalog(
			ctx, bearer, target, body.ResourceType, minimum,
		)
		if err != nil {
			s.failures.Add(1)
			writePermissionAuthoringFailure(writer, err, false, false)
			return true
		}
		s.successes.Add(1)
		writeLegacyJSON(writer, http.StatusOK, response)
	case PermissionAuthoringSavePath:
		var body permissionAuthoringCommandDTO
		if decoder.Decode(&body) != nil || requireJSONEOF(decoder) != nil {
			s.rejectPermissionAuthoring(writer, "Invalid request body")
			return true
		}
		command, valid := permissionAuthoringCommand(body)
		if !valid {
			s.rejectPermissionAuthoring(writer, "Invalid permission command")
			return true
		}
		response, err := s.savePermissionAuthoringWithReconciliation(ctx, bearer, command)
		if err != nil {
			s.failures.Add(1)
			writePermissionAuthoringFailure(writer, err, true, false)
			return true
		}
		s.successes.Add(1)
		writeLegacyJSON(writer, http.StatusOK, projectPermissionAuthoringResult(response))
	case PermissionAuthoringStatusPath:
		var body permissionAuthoringStatusRequestDTO
		if decoder.Decode(&body) != nil || requireJSONEOF(decoder) != nil {
			s.rejectPermissionAuthoring(writer, "Invalid request body")
			return true
		}
		command, valid := permissionAuthoringCommand(body.Command)
		if !valid {
			s.rejectPermissionAuthoring(writer, "Invalid permission command")
			return true
		}
		response, err := s.permissionAuthoringStatusWithReplay(ctx, bearer, command)
		if err != nil {
			s.failures.Add(1)
			writePermissionAuthoringFailure(writer, err, false, true)
			return true
		}
		s.successes.Add(1)
		writeLegacyJSON(writer, http.StatusOK, projectPermissionAuthoringStatus(response))
	}
	return true
}

func (s *Service) rejectPermissionAuthoring(writer http.ResponseWriter, message string) {
	s.localRejected.Add(1)
	s.failures.Add(1)
	writeCRMErrorWith(writer, http.StatusBadRequest, crmwire.SFCodeInvalidRequest, message, writeLegacyJSON)
}

func writePermissionAuthoringFailure(writer http.ResponseWriter, err error, save, status bool) {
	var failure *commonsemantic.Failure
	if !errors.As(err, &failure) {
		if save {
			writeCRMErrorWith(writer, http.StatusInternalServerError, permissionAuthoringOutcomeUnknownCode, "Save result is unknown; check command status", writeLegacyJSON)
			return
		}
		writeRuntimeFailureWith(writer, err, writeLegacyJSON)
		return
	}
	if save {
		if permissionAuthoringOutcomeAmbiguous(err) {
			writeCRMErrorWith(writer, http.StatusServiceUnavailable, permissionAuthoringOutcomeUnknownCode, "Save result is unknown; check command status", writeLegacyJSON)
			return
		}
		switch failure.Category {
		case commonsemantic.FailureStaleState:
			writeCRMErrorWith(writer, http.StatusConflict, permissionAuthoringStaleCode, "Permission state must be refreshed", writeLegacyJSON)
			return
		case commonsemantic.FailureResourceExhausted:
			if failure.LimitKind == commonsemantic.LimitAdmission {
				setRetryAfterHeader(writer, failure.RetryAfterMillis)
				writeCRMErrorWith(writer, http.StatusServiceUnavailable, permissionAuthoringAdmissionCode, "Permission save was not accepted; retry later", writeLegacyJSON)
				return
			}
		}
	}
	if status && failure.Category == commonsemantic.FailureMissing {
		writeCRMErrorWith(writer, http.StatusNotFound, permissionAuthoringCommandMissingCode, "Permission authoring command was not found", writeLegacyJSON)
		return
	}
	writeRuntimeFailureWith(writer, err, writeLegacyJSON)
}
