package usecase

import (
	"context"
	"fmt"
	"strings"

	"github.com/gofrs/uuid/v5"

	"github.com/saveinmed/backend-go/internal/domain"
)

// CreatePaymentPreference builds a checkout preference (e.g. Mercado Pago) for an order.
func (s *Service) CreatePaymentPreference(ctx context.Context, id uuid.UUID) (*domain.PaymentPreference, error) {
	order, err := s.repo.GetOrder(ctx, id)
	if err != nil {
		return nil, err
	}

	buyer, err := s.repo.GetUser(ctx, order.BuyerID)
	if err != nil {
		return nil, fmt.Errorf("failed to fetch buyer: %w", err)
	}

	sellerAcc, err := s.repo.GetSellerPaymentAccount(ctx, order.SellerID)
	if err != nil {
		sellerAcc = nil // Proceed without split if not configured
	}

	return s.pay.CreatePreference(ctx, order, buyer, sellerAcc)
}

// ProcessOrderPayment processes a direct card payment for an order.
// It resolves the buyer (user or B2B company) and delegates to the payment gateway.
func (s *Service) ProcessOrderPayment(ctx context.Context, id uuid.UUID, token, issuerID, paymentMethodID string, installments int, payerEmail, payerDoc string) (*domain.PaymentResult, error) {
	order, err := s.repo.GetOrder(ctx, id)
	if err != nil {
		return nil, err
	}

	var buyer *domain.User
	user, err := s.repo.GetUser(ctx, order.BuyerID)
	if err == nil {
		buyer = user
	} else {
		// B2B fallback: resolve company as payer
		company, errComp := s.repo.GetCompany(ctx, order.BuyerID)
		if errComp != nil {
			return nil, fmt.Errorf("failed to fetch buyer (user or company): %v / %v", err, errComp)
		}
		email := payerEmail
		if email == "" {
			email = "financeiro@saveinmed.com"
		}
		buyer = &domain.User{
			ID:    company.ID,
			Name:  company.CorporateName,
			Email: email,
			CPF:   payerDoc,
		}
		if buyer.CPF == "" {
			buyer.CPF = company.CNPJ
		}
	}

	sellerAcc, err := s.repo.GetSellerPaymentAccount(ctx, order.SellerID)
	if err != nil {
		sellerAcc = nil
	}

	res, err := s.pay.CreatePayment(ctx, order, token, issuerID, paymentMethodID, installments, buyer, sellerAcc)
	if err != nil {
		return nil, err
	}

	if res.Status == "approved" {
		if err := s.UpdateOrderStatus(ctx, order.ID, domain.OrderStatusPaid); err != nil {
			// Payment succeeded; status update failure should be reconciled async.
			fmt.Printf("WARN: payment approved but status update failed: %v\n", err)
		}
	}

	return res, nil
}

// HandlePaymentWebhook processes payment gateway callbacks, updates the order status
// and records the split in the financial ledger.
func (s *Service) HandlePaymentWebhook(ctx context.Context, event domain.PaymentWebhookEvent) (*domain.PaymentSplitResult, error) {
	order, err := s.repo.GetOrder(ctx, event.OrderID)
	if err != nil {
		return nil, err
	}

	expectedMarketplaceFee := int64(float64(order.TotalCents) * (s.marketplaceCommission / 100))
	marketplaceFee := event.MarketplaceFee
	if marketplaceFee == 0 {
		marketplaceFee = expectedMarketplaceFee
	}

	sellerReceivable := order.TotalCents - marketplaceFee
	if event.SellerAmount > 0 {
		sellerReceivable = event.SellerAmount
	}

	if strings.EqualFold(event.Status, "approved") || strings.EqualFold(event.Status, "paid") {
		if err := s.repo.UpdateOrderStatus(ctx, order.ID, domain.OrderStatusPaid); err != nil {
			return nil, err
		}

		_ = s.repo.RecordLedgerEntry(ctx, &domain.LedgerEntry{
			ID:          uuid.Must(uuid.NewV7()),
			CompanyID:   order.SellerID,
			AmountCents: order.TotalCents,
			Type:        "SALE",
			Description: "Order #" + order.ID.String(),
			ReferenceID: &order.ID,
		})

		_ = s.repo.RecordLedgerEntry(ctx, &domain.LedgerEntry{
			ID:          uuid.Must(uuid.NewV7()),
			CompanyID:   order.SellerID,
			AmountCents: -marketplaceFee,
			Type:        "FEE",
			Description: "Marketplace Fee #" + order.ID.String(),
			ReferenceID: &order.ID,
		})
	}

	return &domain.PaymentSplitResult{
		OrderID:          order.ID,
		PaymentID:        event.PaymentID,
		Status:           event.Status,
		MarketplaceFee:   marketplaceFee,
		SellerReceivable: sellerReceivable,
		TotalPaidAmount:  event.TotalPaidAmount,
	}, nil
}
