package automation

import (
	"strings"

	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/approvalir"
)

// decodeApprovalMetadata is the sole production bridge from a product-owned
// approval definition to the legacy runtime projection. CRM runtimes provide a
// decoder through ProductCapabilities; hosts without an approval grammar keep
// the historical compatibility parser until their product supplies one.
func (s *ApprovalService) decodeApprovalMetadata(raw string) (*NormalizedApprovalProcess, error) {
	if strings.TrimSpace(raw) == "" {
		return nil, nil
	}
	if s == nil || s.approvalDefinitionDecoder == nil {
		return ParseApprovalProcessMetadata(raw)
	}
	definition, err := s.approvalDefinitionDecoder.DecodeApprovalDefinition(raw)
	if err != nil {
		return nil, err
	}
	return normalizedApprovalProcessFromDefinition(definition), nil
}

func normalizedApprovalProcessFromDefinition(definition *approvalir.Definition) *NormalizedApprovalProcess {
	if definition == nil {
		return nil
	}

	metadata := &NormalizedApprovalProcess{
		// A product decoder resolves the omitted-policy default before publishing
		// the IR, so every decoded definition has an explicit effective policy.
		HasExplicitAllowedSubmitters: true,
		AllowedSubmitters:            make([]NormalizedAllowedSubmitter, 0, len(definition.Policy.AllowedSubmitters)),
		Steps:                        make([]NormalizedApprovalStep, 0, len(definition.Steps)),
	}
	if definition.ProcessOrder != nil {
		metadata.ProcessOrder = *definition.ProcessOrder
	}
	if definition.HierarchyRouting != nil {
		metadata.NextAutomatedApprover = &NormalizedNextAutomatedApprover{
			UserHierarchyField:            definition.HierarchyRouting.UserHierarchyField,
			UseApproverFieldOfRecordOwner: definition.HierarchyRouting.InitialPrincipal == approvalir.HierarchyInitialPrincipalRecordOwner,
		}
	}
	for _, submitter := range definition.Policy.AllowedSubmitters {
		metadata.AllowedSubmitters = append(metadata.AllowedSubmitters, NormalizedAllowedSubmitter{
			Submitter: strings.TrimSpace(submitter.Submitter),
			Type:      approvalIRSubmitterType(submitter.Kind),
		})
	}
	for _, step := range definition.Steps {
		metadata.Steps = append(metadata.Steps, normalizedApprovalStepFromDefinition(step))
	}
	return metadata
}

func normalizedApprovalStepFromDefinition(step approvalir.Step) NormalizedApprovalStep {
	normalized := NormalizedApprovalStep{
		Name:                  strings.TrimSpace(step.Name),
		Label:                 strings.TrimSpace(step.Label),
		Description:           strings.TrimSpace(step.Description),
		AllowDelegate:         step.AllowDelegate,
		WhenMultipleApprovers: approvalIRMultipleApproverMode(step.MultipleApproverMode),
		RejectBehavior:        approvalIRRejectBehavior(step.RejectBehavior),
		StepCriteria:          normalizedCriteriaFromDefinition(step.Criteria),
		IfCriteriaNotMet:      approvalIRIfCriteriaNotMet(step.IfCriteriaNotMet),
		Approvers:             make([]NormalizedApprovalApprover, 0, len(step.Approvers)),
	}
	for _, approver := range step.Approvers {
		normalized.Approvers = append(normalized.Approvers, NormalizedApprovalApprover{
			Name: strings.TrimSpace(approver.Reference),
			Type: approvalIRApproverType(approver.Kind),
		})
	}
	return normalized
}

func normalizedCriteriaFromDefinition(criteria *approvalir.Criteria) *NormalizedCriteria {
	if criteria == nil {
		return nil
	}
	normalized := &NormalizedCriteria{
		Formula:       strings.TrimSpace(criteria.Formula),
		BooleanFilter: strings.TrimSpace(criteria.BooleanFilter),
		CriteriaItems: make([]NormalizedCriteriaItem, 0, len(criteria.Items)),
	}
	for _, item := range criteria.Items {
		normalized.CriteriaItems = append(normalized.CriteriaItems, NormalizedCriteriaItem{
			Field:     strings.TrimSpace(item.Field),
			Operation: approvalIRCriteriaOperator(item.Operation),
			Value:     item.Value,
		})
	}
	return normalized
}

func approvalIRSubmitterType(kind approvalir.SubmitterKind) string {
	switch kind {
	case approvalir.SubmitterKindAllInternalUsers:
		return constants.ApprovalSubmitterTypeAllInternalUsers
	case approvalir.SubmitterKindRecordCreator:
		return constants.ApprovalSubmitterTypeRecordCreator
	case approvalir.SubmitterKindRecordOwner:
		return constants.ApprovalSubmitterTypeRecordOwner
	case approvalir.SubmitterKindUser:
		return constants.ApprovalSubmitterTypeUser
	case approvalir.SubmitterKindRole:
		return constants.ApprovalSubmitterTypeRole
	case approvalir.SubmitterKindRoleAndSubordinates:
		return constants.ApprovalSubmitterTypeRoleAndSubordinates
	default:
		return string(kind)
	}
}

func approvalIRApproverType(kind approvalir.ApproverKind) string {
	switch kind {
	case approvalir.ApproverKindRelatedUserField:
		return constants.ApprovalApproverTypeRelatedUserField
	case approvalir.ApproverKindUserHierarchyField:
		return constants.ApprovalApproverTypeUserHierarchyField
	case approvalir.ApproverKindPreviousApprover:
		return constants.ApprovalApproverTypePreviousApprover
	case approvalir.ApproverKindAdHoc:
		return constants.ApprovalApproverTypeAdhoc
	case approvalir.ApproverKindUser:
		return constants.ApprovalApproverTypeUser
	case approvalir.ApproverKindQueue:
		return constants.ApprovalApproverTypeQueue
	case approvalir.ApproverKindRole:
		return constants.ApprovalApproverTypeRole
	case approvalir.ApproverKindHierarchy:
		return constants.ApprovalApproverTypeHierarchy
	default:
		return string(kind)
	}
}

func approvalIRMultipleApproverMode(mode approvalir.MultipleApproverMode) string {
	if mode == approvalir.MultipleApproverModeUnanimous {
		return constants.ApprovalModeUnanimous
	}
	return constants.ApprovalModeFirstResponse
}

func approvalIRRejectBehavior(behavior approvalir.RejectBehavior) string {
	switch behavior {
	case approvalir.RejectBehaviorBackToPrevious:
		return constants.ApprovalRejectBehaviorBackToPrevious
	case approvalir.RejectBehaviorBackToSubmitter:
		return constants.ApprovalRejectBehaviorBackToSubmitter
	case approvalir.RejectBehaviorRejectRequest:
		return constants.ApprovalRejectBehaviorRejectRequest
	case approvalir.RejectBehaviorFinalRejection:
		return constants.ApprovalRejectBehaviorFinalRejection
	default:
		return string(behavior)
	}
}

func approvalIRIfCriteriaNotMet(behavior approvalir.IfCriteriaNotMet) string {
	switch behavior {
	case approvalir.IfCriteriaNotMetGotoNextStep:
		return "GotoNextStep"
	case approvalir.IfCriteriaNotMetApprove:
		return "ApproveRecord"
	case approvalir.IfCriteriaNotMetReject:
		return "RejectRecord"
	default:
		return string(behavior)
	}
}

func approvalIRCriteriaOperator(operator approvalir.CriteriaOperator) string {
	switch operator {
	case approvalir.CriteriaOperatorGreaterOrEqual:
		return "greaterOrEqual"
	case approvalir.CriteriaOperatorLessOrEqual:
		return "lessOrEqual"
	case approvalir.CriteriaOperatorGreaterThan:
		return "greaterThan"
	case approvalir.CriteriaOperatorLessThan:
		return "lessThan"
	case approvalir.CriteriaOperatorNotEqual:
		return "notEqual"
	case approvalir.CriteriaOperatorNotContain:
		return "notContain"
	case approvalir.CriteriaOperatorStartsWith:
		return "startsWith"
	case approvalir.CriteriaOperatorContains:
		return "contains"
	case approvalir.CriteriaOperatorExcludes:
		return "excludes"
	case approvalir.CriteriaOperatorIncludes:
		return "includes"
	case approvalir.CriteriaOperatorEquals:
		return "equals"
	default:
		return string(operator)
	}
}
