package handler

import (
	"net/http"
	"strings"

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

// CreatePaymentPreference godoc
// @Summary Cria preferência de pagamento Mercado Pago com split nativo
// @Tags Pagamentos
// @Security BearerAuth
// @Produce json
// @Param id path string true "Order ID"
// @Success 201 {object} domain.PaymentPreference
// @Router /api/v1/orders/{id}/payment [post]
func (h *Handler) CreatePaymentPreference(w http.ResponseWriter, r *http.Request) {
	if !strings.HasSuffix(r.URL.Path, "/payment") {
		http.NotFound(w, r)
		return
	}

	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	pref, err := h.svc.CreatePaymentPreference(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusCreated, pref)
}

// ProcessOrderPayment godoc
// @Summary Processar pagamento direto (Cartão/Pix via Bricks)
// @Router /api/v1/orders/{id}/pay [post]
func (h *Handler) ProcessOrderPayment(w http.ResponseWriter, r *http.Request) {
	id, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	var req struct {
		Token             string  `json:"token"`
		IssuerID          string  `json:"issuer_id"`
		PaymentMethodID   string  `json:"payment_method_id"`
		Installments      int     `json:"installments"`
		TransactionAmount float64 `json:"transaction_amount"`
		Payer             struct {
			Email          string `json:"email"`
			Identification struct {
				Type   string `json:"type"`
				Number string `json:"number"`
			} `json:"identification"`
		} `json:"payer"`
	}
	if err := decodeJSON(r.Context(), r, &req); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	res, err := h.svc.ProcessOrderPayment(r.Context(), id, req.Token, req.IssuerID, req.PaymentMethodID, req.Installments, req.Payer.Email, req.Payer.Identification.Number)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusOK, res)
}

// CreateShipment godoc
// @Summary Gera guia de postagem/transporte
// @Tags Logistica
// @Security BearerAuth
// @Accept json
// @Produce json
// @Param shipment body createShipmentRequest true "Dados de envio"
// @Success 201 {object} domain.Shipment
// @Router /api/v1/shipments [post]
func (h *Handler) CreateShipment(w http.ResponseWriter, r *http.Request) {
	var req createShipmentRequest
	if err := decodeJSON(r.Context(), r, &req); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	shipment := &domain.Shipment{
		OrderID:          req.OrderID,
		Carrier:          req.Carrier,
		TrackingCode:     req.TrackingCode,
		ExternalTracking: req.ExternalTracking,
	}

	if err := h.svc.CreateShipment(r.Context(), shipment); err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusCreated, shipment)
}

// GetShipmentByOrderID godoc
// @Summary Rastreia entrega
// @Tags Logistica
// @Security BearerAuth
// @Produce json
// @Param order_id path string true "Order ID"
// @Success 200 {object} domain.Shipment
// @Router /api/v1/shipments/{order_id} [get]
func (h *Handler) GetShipmentByOrderID(w http.ResponseWriter, r *http.Request) {
	orderID, err := parseUUIDFromPath(r.URL.Path)
	if err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	shipment, err := h.svc.GetShipmentByOrderID(r.Context(), orderID)
	if err != nil {
		writeError(w, http.StatusNotFound, err)
		return
	}

	writeJSON(w, http.StatusOK, shipment)
}

// HandlePaymentWebhook godoc
// @Summary Recebe notificações do Mercado Pago
// @Tags Pagamentos
// @Accept json
// @Produce json
// @Param notification body domain.PaymentWebhookEvent true "Evento do gateway"
// @Success 200 {object} domain.PaymentSplitResult
// @Router /api/v1/payments/webhook [post]
func (h *Handler) HandlePaymentWebhook(w http.ResponseWriter, r *http.Request) {
	var event domain.PaymentWebhookEvent
	if err := decodeJSON(r.Context(), r, &event); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	summary, err := h.svc.HandlePaymentWebhook(r.Context(), event)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

	writeJSON(w, http.StatusOK, summary)
}

// HandleStripeWebhook godoc
// @Summary Recebe notificações do Stripe
// @Tags Pagamentos
// @Accept json
// @Produce json
// @Success 200 {object} map[string]string
// @Router /api/v1/payments/webhook/stripe [post]
func (h *Handler) HandleStripeWebhook(w http.ResponseWriter, r *http.Request) {
	// In production: Verify Stripe-Signature header using the raw body
	// signature := r.Header.Get("Stripe-Signature")

	var payload struct {
		Type string `json:"type"`
		Data struct {
			Object struct {
				ID       string `json:"id"`
				Metadata struct {
					OrderID string `json:"order_id"`
				} `json:"metadata"`
				Status         string `json:"status"`
				AmountReceived int64  `json:"amount_received"`
				ApplicationFee int64  `json:"application_fee_amount"`
				TransferData   struct {
					Amount int64 `json:"amount"` // Seller amount
				} `json:"transfer_data"`
			} `json:"object"`
		} `json:"data"`
	}

	if err := decodeJSON(r.Context(), r, &payload); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	// Map Stripe event to generic domain event
	if payload.Type == "payment_intent.succeeded" {
		orderID, _ := uuid.FromString(payload.Data.Object.Metadata.OrderID)
		event := domain.PaymentWebhookEvent{
			PaymentID:       payload.Data.Object.ID,
			OrderID:         orderID,
			Status:          "approved", // Stripe succeeded = approved
			TotalPaidAmount: payload.Data.Object.AmountReceived,
			MarketplaceFee:  payload.Data.Object.ApplicationFee,
			SellerAmount:    payload.Data.Object.TransferData.Amount,
		}

		if _, err := h.svc.HandlePaymentWebhook(r.Context(), event); err != nil {
			writeError(w, http.StatusInternalServerError, err)
			return
		}
	}

	writeJSON(w, http.StatusOK, map[string]string{"received": "true"})
}

// HandleAsaasWebhook godoc
// @Summary Recebe notificações do Asaas
// @Tags Pagamentos
// @Accept json
// @Produce json
// @Success 200 {object} map[string]string
// @Router /api/v1/payments/webhook/asaas [post]
func (h *Handler) HandleAsaasWebhook(w http.ResponseWriter, r *http.Request) {
	// In production: Verify asaas-access-token header
	// token := r.Header.Get("asaas-access-token")

	var payload struct {
		Event   string `json:"event"`
		Payment struct {
			ID          string  `json:"id"`
			ExternalRef string  `json:"externalReference"` // We store OrderID here
			Status      string  `json:"status"`
			NetValue    int64   `json:"netValue"` // value after fees? Need to check docs.
			Value       float64 `json:"value"`    // Asaas sends float
			Split       []struct {
				WalletID   string  `json:"walletId"`
				FixedValue float64 `json:"fixedValue"`
			} `json:"split"`
		} `json:"payment"`
	}

	if err := decodeJSON(r.Context(), r, &payload); err != nil {
		writeError(w, http.StatusBadRequest, err)
		return
	}

	if payload.Event == "PAYMENT_RECEIVED" || payload.Event == "PAYMENT_CONFIRMED" {
		orderID, _ := uuid.FromString(payload.Payment.ExternalRef)

		// Convert Asaas float value to cents
		totalCents := int64(payload.Payment.Value * 100)

		// Find split part for marketplace/seller
		// This logic depends on how we set up the split.
		// For now, simpler mapping:

		event := domain.PaymentWebhookEvent{
			PaymentID:       payload.Payment.ID,
			OrderID:         orderID,
			Status:          "approved",
			TotalPaidAmount: totalCents,
			// MarketplaceFee and SellerAmount might need calculation or extraction from split array
		}

		if _, err := h.svc.HandlePaymentWebhook(r.Context(), event); err != nil {
			writeError(w, http.StatusInternalServerError, err)
			return
		}
	}

	writeJSON(w, http.StatusOK, map[string]string{"received": "true"})
}
