package quote_computation_service

import (
	"context"

	"github.com/tech/sendico/pkg/merrors"
	"go.uber.org/zap"
)

func (s *QuoteComputationService) Compute(ctx context.Context, in ComputeInput) (*ComputeOutput, error) {
	if s == nil || s.core == nil {
		return nil, merrors.InvalidArgument("quote computation core is required")
	}

	s.logger.Debug("Computing quotes",
		zap.String("org_ref", in.OrganizationRef),
		zap.Int("intent_count", len(in.Intents)),
		zap.Bool("preview_only", in.PreviewOnly),
	)

	planModel, err := s.BuildPlan(ctx, in)
	if err != nil {
		s.logger.Warn("Quote plan build failed",
			zap.String("org_ref", in.OrganizationRef),
			zap.Error(err),
		)

		return nil, err
	}

	results := make([]*QuoteComputationResult, 0, len(planModel.Items))
	for _, item := range planModel.Items {
		computed, computeErr := s.computePlanItem(ctx, item)
		if computeErr != nil {
			if item == nil {
				return nil, computeErr
			}

			s.logger.Warn("Quote item computation failed",
				zap.String("org_ref", in.OrganizationRef),
				zap.Int("item_index", item.Index),
				zap.String("intent_ref", item.IntentRef),
				zap.Error(computeErr),
			)

			return nil, wrapIndexedError(computeErr, "Item %d", item.Index)
		}

		results = append(results, computed)
	}

	s.logger.Debug("Quote computation completed",
		zap.String("org_ref", in.OrganizationRef),
		zap.String("plan_mode", string(planModel.Mode)),
		zap.Int("item_count", len(results)),
	)

	return &ComputeOutput{
		Plan:    planModel,
		Results: results,
	}, nil
}

func (s *QuoteComputationService) computePlanItem(
	ctx context.Context,
	item *QuoteComputationPlanItem,
) (*QuoteComputationResult, error) {
	if item == nil || item.QuoteInput.Intent.Amount == nil {
		return nil, merrors.InvalidArgument("plan item is required")
	}

	quote, expiresAt, err := s.core.BuildQuote(ctx, item.QuoteInput)
	if err != nil {
		s.logger.Warn("Quote build failed",
			zap.Int("item_index", item.Index),
			zap.String("intent_ref", item.IntentRef),
			zap.Error(err),
		)

		return nil, err
	}

	enrichedQuote := ensureComputedQuote(quote, item)
	if bindErr := validateQuoteRouteBinding(enrichedQuote, item.QuoteInput); bindErr != nil {
		s.logger.Warn("Quote route binding validation failed",
			zap.Int("item_index", item.Index),
			zap.String("intent_ref", item.IntentRef),
			zap.Error(bindErr),
		)

		return nil, bindErr
	}

	s.logger.Debug("Quote item computed",
		zap.Int("item_index", item.Index),
		zap.String("intent_ref", item.IntentRef),
		zap.String("quote_ref", enrichedQuote.QuoteRef),
		zap.Time("expires_at", expiresAt),
		zap.String("block_reason", item.BlockReason.String()),
	)

	return &QuoteComputationResult{
		ItemIndex:   item.Index,
		Quote:       enrichedQuote,
		ExpiresAt:   expiresAt,
		BlockReason: item.BlockReason,
	}, nil
}
