package controllers

import (
	"strings"

	"github.com/gofiber/fiber/v2"
	"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
	"github.com/sujit-baniya/fiber-boilerplate/pkg/services"
)

func servicioPagoDeContexto(c *fiber.Ctx) (*models.ServicioPagoExterno, error) {
	servicio, ok := c.Locals("servicio_pago").(*models.ServicioPagoExterno)
	if !ok || servicio == nil {
		return nil, fiber.NewError(fiber.StatusUnauthorized, "no autenticado")
	}
	return servicio, nil
}

// PasarelasDisponiblesHandler indica qué pasarelas puede usar el token actual.
// Ruta: GET /api/v1/pagos-externos/pasarelas
func PasarelasDisponiblesHandler(c *fiber.Ctx) error {
	servicio, err := servicioPagoDeContexto(c)
	if err != nil {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": true, "message": err.Error()})
	}
	return c.JSON(fiber.Map{"pasarelas": servicio.PasarelasList()})
}

// SolicitarPagoExternoHandler crea un cobro nuevo con el token autenticado.
// Ruta: POST /api/v1/pagos-externos/solicitar
func SolicitarPagoExternoHandler(c *fiber.Ctx) error {
	servicio, err := servicioPagoDeContexto(c)
	if err != nil {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": true, "message": err.Error()})
	}

	var req struct {
		ReferenciaExterna string  `json:"referencia_externa"`
		Pasarela          string  `json:"pasarela"`
		Monto             float64 `json:"monto"`
		Moneda            string  `json:"moneda"`
		Descripcion       string  `json:"descripcion"`
		ClienteID         *uint   `json:"cliente_id"`
	}
	if err := c.BodyParser(&req); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": true, "message": "body inválido"})
	}
	if strings.TrimSpace(req.ReferenciaExterna) == "" {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": true, "message": "referencia_externa es requerida"})
	}

	solicitud, err := services.SolicitarPagoExterno(
		servicio,
		strings.TrimSpace(req.ReferenciaExterna),
		strings.ToLower(strings.TrimSpace(req.Pasarela)),
		strings.TrimSpace(req.Descripcion),
		strings.ToUpper(strings.TrimSpace(req.Moneda)),
		req.Monto,
		req.ClienteID,
	)
	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": true, "message": err.Error()})
	}

	return c.Status(fiber.StatusCreated).JSON(fiber.Map{
		"referencia_externa": solicitud.ReferenciaExterna,
		"referencia_interna": solicitud.ReferenciaInterna,
		"enlace_pago":        solicitud.EnlacePago,
		"pasarela":           solicitud.Pasarela,
		"estado":             solicitud.Estado,
		"monto":              solicitud.Monto,
		"moneda":             solicitud.Moneda,
	})
}

// EstadoPagoExternoHandler consulta el estado de un cobro. Solo devuelve datos
// si la solicitud pertenece al mismo servicio autenticado, para que un token
// no pueda enumerar/consultar solicitudes de otro cliente.
// Ruta: GET /api/v1/pagos-externos/:referencia/estado
func EstadoPagoExternoHandler(c *fiber.Ctx) error {
	servicio, err := servicioPagoDeContexto(c)
	if err != nil {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": true, "message": err.Error()})
	}
	referencia := c.Params("referencia")

	solicitud, err := models.GetSolicitudPagoExternaByReferenciaInterna(referencia)
	if err != nil || solicitud.ServicioID != servicio.ID {
		return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": true, "message": "solicitud no encontrada"})
	}

	return c.JSON(fiber.Map{
		"referencia_externa": solicitud.ReferenciaExterna,
		"referencia_interna": solicitud.ReferenciaInterna,
		"estado":             solicitud.Estado,
		"pasarela":           solicitud.Pasarela,
		"monto":              solicitud.Monto,
		"moneda":             solicitud.Moneda,
		"fecha_pago":         solicitud.FechaPago,
	})
}
