package dialectsfcrm

import (
	"bytes"
	"encoding/json"
	"fmt"
	"strings"

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

// decodeApprovalProcessManagedRequest proves that the lifecycle request still
// represents the exact canonical projection built from its lossless source
// payload. All per-component callbacks share this read path.
func decodeApprovalProcessManagedRequest(request cp.ComponentManagedRequest) (ApprovalProcessPersistencePlan, error) {
	if request.PackName == "" || strings.TrimSpace(request.PackName) != request.PackName {
		return ApprovalProcessPersistencePlan{}, fmt.Errorf("pack name %q is not canonical", request.PackName)
	}
	if request.SourceOwner != "" {
		return ApprovalProcessPersistencePlan{}, fmt.Errorf("pack-owned approval process must not declare source owner %q", request.SourceOwner)
	}
	if request.Component.Kind != cp.ComponentKindApprovalProcess {
		return ApprovalProcessPersistencePlan{}, fmt.Errorf("component kind = %q, want %q", request.Component.Kind, cp.ComponentKindApprovalProcess)
	}
	if request.Component.Manageability != cp.ManageabilityLocked {
		return ApprovalProcessPersistencePlan{}, fmt.Errorf("approval process %q manageability must be %q, got %q", request.Component.BusinessKey, cp.ManageabilityLocked, request.Component.Manageability)
	}
	if len(request.Payload) == 0 || (len(request.Component.Payload) > 0 && !bytes.Equal(request.Component.Payload, request.Payload)) {
		return ApprovalProcessPersistencePlan{}, fmt.Errorf("approval process %q lifecycle payload is required and any inline component payload must exactly match it", request.Component.BusinessKey)
	}
	objectAPIName, developerName, err := splitApprovalProcessComponentBusinessKey(request.Component.BusinessKey)
	if err != nil {
		return ApprovalProcessPersistencePlan{}, err
	}
	metadata, err := DecodeApprovalProcessMetadata(string(request.Payload))
	if err != nil {
		return ApprovalProcessPersistencePlan{}, fmt.Errorf("decode approval process %s/%s: %w", objectAPIName, developerName, err)
	}
	canonical, err := PlanApprovalProcessPersistence(ApprovalProcessProjectionRequest{
		ObjectAPIName:     objectAPIName,
		DeveloperName:     developerName,
		ParentDisposition: ApprovalProcessParentManagedUpsert,
		OwnerPack:         request.PackName,
		RawMetadata:       string(request.Payload),
		Metadata:          metadata,
	})
	if err != nil {
		return ApprovalProcessPersistencePlan{}, err
	}
	canonicalJSON, err := json.Marshal(canonical)
	if err != nil {
		return ApprovalProcessPersistencePlan{}, fmt.Errorf("marshal approval process %s/%s canonical projection: %w", objectAPIName, developerName, err)
	}
	if !bytes.Equal(canonicalJSON, request.ExpectedProjection) {
		return ApprovalProcessPersistencePlan{}, fmt.Errorf("approval process %s/%s expected projection does not match its canonical source payload", objectAPIName, developerName)
	}
	return canonical, nil
}
