package transfer_intent_hydrator

import (
	"context"
	"strings"

	"github.com/tech/sendico/pkg/merrors"
	endpointv1 "github.com/tech/sendico/pkg/proto/payments/endpoint/v1"
	methodsv1 "github.com/tech/sendico/pkg/proto/payments/methods/v1"
)

func (h *TransferIntentHydrator) hydrateEndpoint(
	ctx context.Context,
	organizationRef string,
	endpoint *endpointv1.PaymentEndpoint,
	field string,
	role methodsv1.PrivateEndpoint,
) (QuoteEndpoint, error) {
	if endpoint == nil {
		return QuoteEndpoint{}, merrors.InvalidArgument(field + " is required")
	}

	if methodRef := strings.TrimSpace(endpoint.GetPaymentMethodRef()); methodRef != "" {
		resolved, resolvedMethodRef, err := h.resolvePrivate(ctx, organizationRef, field+".payment_method_ref", role, privateSelector{
			paymentMethodRef: methodRef,
		})
		if err != nil {
			return QuoteEndpoint{}, err
		}
		if resolvedMethodRef != "" {
			resolved.PaymentMethodRef = resolvedMethodRef
		} else {
			resolved.PaymentMethodRef = methodRef
		}
		return resolved, nil
	}

	if method := endpoint.GetPaymentMethod(); method != nil {
		if method.GetType() != endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_ACCOUNT {
			return hydrateFromPaymentMethod(method, field)
		}
		recipientRef := strings.TrimSpace(method.GetRecipientRef())
		if recipientRef == "" {
			return QuoteEndpoint{}, merrors.InvalidArgument(field + ".payment_method.recipient_ref is required for account payment method")
		}
		resolved, resolvedMethodRef, err := h.resolvePrivate(ctx, organizationRef, field+".payment_method", role, privateSelector{
			payeeRef: recipientRef,
		})
		if err != nil {
			return QuoteEndpoint{}, err
		}
		if resolvedMethodRef != "" {
			resolved.PaymentMethodRef = resolvedMethodRef
		}
		return resolved, nil
	}

	if payeeRef := strings.TrimSpace(endpoint.GetPayeeRef()); payeeRef != "" {
		resolved, resolvedMethodRef, err := h.resolvePrivate(ctx, organizationRef, field+".payee_ref", role, privateSelector{
			payeeRef: payeeRef,
		})
		if err != nil {
			return QuoteEndpoint{}, err
		}
		resolved.PayeeRef = payeeRef
		resolved.PaymentMethodRef = resolvedMethodRef
		return resolved, nil
	}

	return QuoteEndpoint{}, merrors.InvalidArgument(field + " must include payment_method_ref, payment_method, or payee_ref")
}

type privateSelector struct {
	paymentMethodRef string
	payeeRef         string
}

func (h *TransferIntentHydrator) resolvePrivate(
	ctx context.Context,
	organizationRef string,
	field string,
	role methodsv1.PrivateEndpoint,
	selector privateSelector,
) (QuoteEndpoint, string, error) {
	if h.methodsClient == nil {
		return QuoteEndpoint{}, "", ErrPaymentMethodsClientRequired
	}

	req := &methodsv1.GetPaymentMethodPrivateRequest{
		OrganizationRef: strings.TrimSpace(organizationRef),
		Endpoint:        role,
	}
	if selector.paymentMethodRef != "" {
		req.Selector = &methodsv1.GetPaymentMethodPrivateRequest_PaymentMethodRef{
			PaymentMethodRef: strings.TrimSpace(selector.paymentMethodRef),
		}
	}
	if selector.payeeRef != "" {
		req.Selector = &methodsv1.GetPaymentMethodPrivateRequest_PayeeRef{
			PayeeRef: strings.TrimSpace(selector.payeeRef),
		}
	}

	resp, err := h.methodsClient.GetPaymentMethodPrivate(ctx, req)
	if err != nil {
		return QuoteEndpoint{}, "", err
	}
	record := resp.GetPaymentMethodRecord()
	if record == nil || record.GetPaymentMethod() == nil {
		return QuoteEndpoint{}, "", merrors.InvalidArgument(field + " not found")
	}

	resolved, err := hydrateFromPaymentMethod(record.GetPaymentMethod(), field)
	if err != nil {
		return QuoteEndpoint{}, "", err
	}

	methodRef := strings.TrimSpace(record.GetPermissionBound().GetStorable().GetId())
	return resolved, methodRef, nil
}

/*
Processing Classes

QuoteRequestValidatorV2
Validates meta, idempotency, preview rules, initiator_ref, non-empty intents.
TransferIntentHydrator
Converts transferv1.TransferIntent to canonical sharedv1.PaymentIntent.
Resolves endpoint refs (payment_method_ref, payee_ref) using a new methods dependency.
Applies defaults for kind, settlement_mode, settlement_currency, attributes.
QuoteIdempotencyService
Computes request fingerprint for v2 requests.
Reuse/create logic against QuotesStore (same pattern as handlers_commands.go).
QuoteComputationService
Calls existing core for quote and plan building.
Returns quote + expiry + optional plan.
QuoteExecutabilityClassifier
Converts plan/build errors to QuoteBlockReason.
Produces quote state (executable/blocked/indicative + block_reason when blocked).
QuotePersistenceService
Persists quote record with v2 status metadata.
QuoteResponseMapperV2
Maps canonical quote + status to quotationv2.PaymentQuote.
Enforces your lifecycle/execution invariants.
BatchQuoteProcessorV2
Iterates single-intent processor with per-item idempotency derivation.
Returns QuotePaymentsResponse without aggregate.

*/
