package orchestrator

import (
	"context"

	"github.com/tech/sendico/payments/orchestrator/storage/model"
	"github.com/tech/sendico/pkg/merrors"
	orchestratorv1 "github.com/tech/sendico/pkg/proto/payments/orchestrator/v1"
)

type defaultPlanBuilder struct{}

func (b *defaultPlanBuilder) Build(ctx context.Context, payment *model.Payment, quote *orchestratorv1.PaymentQuote, routes RouteStore, templates PlanTemplateStore, gateways GatewayRegistry) (*model.PaymentPlan, error) {
	if payment == nil {
		return nil, merrors.InvalidArgument("plan builder: payment is required")
	}
	if routes == nil {
		return nil, merrors.InvalidArgument("plan builder: routes store is required")
	}
	if templates == nil {
		return nil, merrors.InvalidArgument("plan builder: plan templates store is required")
	}

	intent := payment.Intent
	if intent.Kind == model.PaymentKindFXConversion {
		return buildFXConversionPlan(payment)
	}

	sourceRail, sourceNetwork, err := railFromEndpoint(intent.Source, intent.Attributes, true)
	if err != nil {
		return nil, err
	}
	destRail, destNetwork, err := railFromEndpoint(intent.Destination, intent.Attributes, false)
	if err != nil {
		return nil, err
	}

	if sourceRail == model.RailUnspecified || destRail == model.RailUnspecified {
		return nil, merrors.InvalidArgument("plan builder: source and destination rails are required")
	}
	if sourceRail == destRail {
		if sourceRail == model.RailLedger {
			return buildLedgerTransferPlan(payment)
		}
		return nil, merrors.InvalidArgument("plan builder: unsupported same-rail payment")
	}

	network, err := resolveRouteNetwork(intent.Attributes, sourceNetwork, destNetwork)
	if err != nil {
		return nil, err
	}

	if _, err := selectRoute(ctx, routes, sourceRail, destRail, network); err != nil {
		return nil, err
	}

	template, err := selectPlanTemplate(ctx, templates, sourceRail, destRail, network)
	if err != nil {
		return nil, err
	}

	return b.buildPlanFromTemplate(ctx, payment, quote, template, sourceRail, destRail, sourceNetwork, destNetwork, gateways)
}
