package handlers

import (
	"encoding/json"
	"log"
	"time"

	"lune/talentscale/internal/modules/billing/dto"
	"lune/talentscale/internal/modules/billing/services"

	"github.com/gofiber/fiber/v2"
)

// WebhookHandler handles Midtrans payment webhook
type WebhookHandler struct {
	billing *services.BillingService
}

// NewWebhookHandler creates a new webhook handler
func NewWebhookHandler(billing *services.BillingService) *WebhookHandler {
	return &WebhookHandler{billing: billing}
}

// HandleMidtransWebhook handles POST /api/public/payments/midtrans/webhook
//
// CRITICAL: This endpoint MUST be idempotent.
// Midtrans may send the same webhook multiple times.
//
// Flow:
//  1. Parse notification payload
//  2. Verify signature (SHA512)
//  3. Check idempotency (skip if already processed)
//  4. Lock payment row (FOR UPDATE)
//  5. Update payment + invoice status
//  6. If success: create/extend subscription + add quota
//  7. If failed: update statuses
//  8. Send email notifications (async)
//  9. Return 200 OK (always, to prevent Midtrans retries)
func (h *WebhookHandler) HandleMidtransWebhook(c *fiber.Ctx) error {
	startTime := time.Now()

	// 1. Parse raw body
	rawBody := c.Body()
	if len(rawBody) == 0 {
		log.Printf("⚠️ Webhook received empty body")
		return c.Status(fiber.StatusOK).JSON(fiber.Map{"status": "ignored"})
	}

	// 2. Parse notification
	var notification dto.MidtransNotification
	if err := json.Unmarshal(rawBody, &notification); err != nil {
		log.Printf("⚠️ Webhook parse error: %v", err)
		// Return 200 to prevent Midtrans retry on malformed payload
		return c.Status(fiber.StatusOK).JSON(fiber.Map{"status": "parse_error"})
	}

	// 3. Serialize headers for logging
	headersMap := make(map[string]string)
	c.Request().Header.VisitAll(func(key, value []byte) {
		headersMap[string(key)] = string(value)
	})
	rawHeaders, _ := json.Marshal(headersMap)

	log.Printf("📥 Webhook received: order_id=%s status=%s payment_type=%s",
		notification.OrderID, notification.TransactionStatus, notification.PaymentType)

	// 4. Process webhook
	if err := h.billing.HandleWebhook(c.Context(), &notification, rawBody, rawHeaders); err != nil {
		log.Printf("❌ Webhook processing error: %v (order_id=%s)", err, notification.OrderID)
		// Still return 200 to prevent infinite retry loops
		// The error is logged and can be investigated
		return c.Status(fiber.StatusOK).JSON(fiber.Map{"status": "error", "message": err.Error()})
	}

	elapsed := time.Since(startTime)
	log.Printf("✅ Webhook processed successfully: order_id=%s elapsed=%v", notification.OrderID, elapsed)

	return c.Status(fiber.StatusOK).JSON(fiber.Map{"status": "ok"})
}
