package sexec

import (
	"context"

	"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/agg"

	"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/xplan"
	"github.com/tech/sendico/pkg/mlogger"
	"go.uber.org/zap"
)

// Registry dispatches orchestration steps to rail/action-specific executors.
type Registry interface {
	Execute(ctx context.Context, in ExecuteInput) (*ExecuteOutput, error)
}

// ExecuteInput is the step-execution payload.
type ExecuteInput struct {
	Payment       *agg.Payment
	Step          xplan.Step
	StepExecution agg.StepExecution
}

// ExecuteOutput is the executor result for one step.
type ExecuteOutput struct {
	StepExecution agg.StepExecution
	Async         bool
}

// StepRequest is the normalized request passed to concrete executors.
type StepRequest struct {
	Payment       *agg.Payment
	Step          xplan.Step
	StepExecution agg.StepExecution
}

// LedgerExecutor handles ledger-bound actions.
type LedgerExecutor interface {
	ExecuteLedger(ctx context.Context, req StepRequest) (*ExecuteOutput, error)
}

// CryptoExecutor handles crypto rail SEND/FEE actions.
type CryptoExecutor interface {
	ExecuteCrypto(ctx context.Context, req StepRequest) (*ExecuteOutput, error)
}

// ProviderSettlementExecutor handles settlement FX_CONVERT actions.
type ProviderSettlementExecutor interface {
	ExecuteProviderSettlement(ctx context.Context, req StepRequest) (*ExecuteOutput, error)
}

// CardPayoutExecutor handles card payout SEND actions.
type CardPayoutExecutor interface {
	ExecuteCardPayout(ctx context.Context, req StepRequest) (*ExecuteOutput, error)
}

// ObserveConfirmExecutor handles OBSERVE_CONFIRM actions.
type ObserveConfirmExecutor interface {
	ExecuteObserveConfirm(ctx context.Context, req StepRequest) (*ExecuteOutput, error)
}

// GuardExecutor handles non-rail guard steps (liquidity/prefunding).
type GuardExecutor interface {
	ExecuteGuard(ctx context.Context, req StepRequest) (*ExecuteOutput, error)
}

// Dependencies defines concrete executors used by the registry.
type Dependencies struct {
	Logger             mlogger.Logger
	Ledger             LedgerExecutor
	Crypto             CryptoExecutor
	ProviderSettlement ProviderSettlementExecutor
	CardPayout         CardPayoutExecutor
	ObserveConfirm     ObserveConfirmExecutor
	Guard              GuardExecutor
}

func New(deps Dependencies) Registry {
	logger := deps.Logger
	if logger == nil {
		logger = zap.NewNop()
	}
	return &svc{
		logger: logger.Named("executor"),
		deps:   deps,
	}
}
