package psvc

import (
	"context"
	"time"

	"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/agg"
	"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/erecon"
	"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/idem"
	"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/oobs"
	"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/opagg"
	"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/ostate"
	"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/pquery"
	"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/prepo"
	"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/prmap"
	"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/qsnap"
	"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/reqval"
	"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/sexec"
	"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/ssched"
	"github.com/tech/sendico/payments/orchestrator/internal/service/orchestrationv2/xplan"
	msg "github.com/tech/sendico/pkg/messaging"
	"github.com/tech/sendico/pkg/mlogger"
	orchestrationv2 "github.com/tech/sendico/pkg/proto/payments/orchestration/v2"
)

// Service orchestrates execute/query/reconcile payment runtime operations.
type Service interface {
	ExecutePayment(ctx context.Context, req *orchestrationv2.ExecutePaymentRequest) (*orchestrationv2.ExecutePaymentResponse, error)
	ExecuteBatchPayment(ctx context.Context, req *orchestrationv2.ExecuteBatchPaymentRequest) (*orchestrationv2.ExecuteBatchPaymentResponse, error)
	GetPayment(ctx context.Context, req *orchestrationv2.GetPaymentRequest) (*orchestrationv2.GetPaymentResponse, error)
	ListPayments(ctx context.Context, req *orchestrationv2.ListPaymentsRequest) (*orchestrationv2.ListPaymentsResponse, error)

	ReconcileExternal(ctx context.Context, in ReconcileExternalInput) (*ReconcileExternalOutput, error)
}

// ReconcileExternalInput is one internal external-event payload.
type ReconcileExternalInput struct {
	OrganizationRef string
	PaymentRef      string
	Event           erecon.Event
}

// ReconcileExternalOutput is reconciliation result payload.
type ReconcileExternalOutput struct {
	Payment *orchestrationv2.Payment
}

// Dependencies configures orchestration-v2 runtime modules.
type Dependencies struct {
	Logger mlogger.Logger

	QuoteStore qsnap.Store

	Validator      reqval.Validator
	Idempotency    idem.Service
	Quote          qsnap.Resolver
	BatchOptimizer BatchOptimizer
	Aggregator     opagg.Aggregator
	Aggregate      agg.Factory
	Planner        xplan.Compiler
	State          ostate.StateMachine
	Scheduler      ssched.Runtime
	Executors      sexec.Registry
	Reconciler     erecon.Reconciler
	Repository     prepo.Repository
	Query          pquery.Service
	Mapper         prmap.Mapper
	Observer       oobs.Observer
	Producer       msg.Producer

	RetryPolicy             ssched.RetryPolicy
	BatchOptimizationPolicy BatchOptimizationPolicy
	Now                     func() time.Time
	MaxTicks                int
}

func New(deps Dependencies) (Service, error) {
	return newService(deps)
}
