package dialectsfcrm

import (
	"context"
	"fmt"
	"strings"

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

// ApprovalProcessChildSyncCapability is the CRM-owned lifecycle capability that
// materializes ProcessNode/ProcessAction rows from ProcessDefinition.Metadata.
// Object metadata decides which objects/phases use it; L0 only dispatches the
// capability.
const ApprovalProcessChildSyncCapability = "crm.approval-process-child-sync"

// ApprovalProcessOwnerlessLifecycleStore is the transaction-scoped host store
// needed to reconcile children for an already-written ownerless definition.
// The records engine owns the surrounding transaction.
type ApprovalProcessOwnerlessLifecycleStore interface {
	cp.ComponentMutationStore
	ResolveApprovalProcessUserID(ctx context.Context, username string, user *models.UserSession) (string, error)
}

// NewApprovalProcessOwnerlessLifecycleHook constructs the ownerless child
// materializer. Registration and writer selection remain host-owned.
func NewApprovalProcessOwnerlessLifecycleHook(store ApprovalProcessOwnerlessLifecycleStore) (contract.RecordLifecycleHook, error) {
	if store == nil {
		return nil, fmt.Errorf("approval-process ownerless lifecycle store is required")
	}
	return approvalProcessOwnerlessLifecycleAdapter{store: store}.Handle, nil
}

type approvalProcessOwnerlessLifecycleAdapter struct {
	store ApprovalProcessOwnerlessLifecycleStore
}

func (a approvalProcessOwnerlessLifecycleAdapter) Handle(ctx context.Context, event contract.RecordLifecycleEvent) error {
	if !strings.EqualFold(event.ObjectName, constants.TableProcessDefinition) {
		return fmt.Errorf("approval-process ownerless lifecycle hook can only run on %s, got %s", constants.TableProcessDefinition, event.ObjectName)
	}
	if event.RecordID == "" || strings.TrimSpace(event.RecordID) != event.RecordID {
		return fmt.Errorf("approval-process ownerless lifecycle hook requires canonical %s", constants.FieldID)
	}
	rawMetadata, ok := event.Record[constants.FieldProcessDefinition_Metadata].(string)
	if !ok || strings.TrimSpace(rawMetadata) == "" {
		return nil
	}
	if oldMetadata, ok := event.OldRecord[constants.FieldProcessDefinition_Metadata].(string); ok && oldMetadata == rawMetadata {
		return nil
	}

	developerName, err := approvalProcessOwnerlessLifecycleIdentity(event.Record, "DeveloperName")
	if err != nil {
		return err
	}
	objectAPIName, err := approvalProcessOwnerlessLifecycleIdentity(event.Record, "TableEnumOrId")
	if err != nil {
		return err
	}
	metadata, err := DecodeApprovalProcessMetadata(rawMetadata)
	if err != nil {
		return fmt.Errorf("invalid approval-process metadata: %w", err)
	}
	plan, err := PlanApprovalProcessPersistence(ApprovalProcessProjectionRequest{
		ObjectAPIName: objectAPIName, DeveloperName: developerName,
		ParentDisposition:  ApprovalProcessParentPreAppliedOwnerless,
		OwnerPack:          "",
		PreAppliedParentID: event.RecordID, RawMetadata: rawMetadata, Metadata: metadata,
	})
	if err != nil {
		return fmt.Errorf("plan ownerless approval-process persistence: %w", err)
	}
	return reconcileApprovalProcessPersistencePlan(ctx, a.store, plan, func(ctx context.Context, username string) (string, error) {
		return a.store.ResolveApprovalProcessUserID(ctx, username, event.CurrentUser)
	})
}

func approvalProcessOwnerlessLifecycleIdentity(record contract.Record, field string) (string, error) {
	value, ok := record[field].(string)
	if !ok || value == "" || strings.TrimSpace(value) != value {
		return "", fmt.Errorf("approval-process ownerless lifecycle hook requires canonical %s", field)
	}
	return value, nil
}
