package es.tatvil.taiageweb.controlador;

import com.stripe.exception.StripeException;
import com.stripe.model.checkout.Session;
import com.stripe.param.checkout.SessionCreateParams;
import es.tatvil.taiageweb.repositorio.UsuarioRepository;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

/**
 * Controlador MVC para el flujo de pago con Stripe.
 *
 * <p>Gestiona tres pasos del proceso de compra:</p>
 * <ol>
 *   <li>Mostrar la página informativa con precio ({@code GET /pagar}).</li>
 *   <li>Crear la sesión de checkout en Stripe y redirigir al usuario
 *       ({@code POST /pagar/iniciar}).</li>
 *   <li>Mostrar páginas de éxito o cancelación tras volver de Stripe.</li>
 * </ol>
 *
 * <p>La concesión real del acceso ocurre vía webhook en
 * {@link WebhookController}, no en las páginas de retorno de Stripe.</p>
 */
@Controller
public class PagoController {

    @Value("${stripe.price-amount}")
    private long priceAmount;

    @Value("${stripe.currency}")
    private String currency;

    private final UsuarioRepository usuarioRepo;

    /**
     * Constructor con inyección de dependencias.
     *
     * @param usuarioRepo repositorio de usuarios
     */
    public PagoController(UsuarioRepository usuarioRepo) {
        this.usuarioRepo = usuarioRepo;
    }

    /**
     * Muestra la página informativa de pago con el precio actual.
     *
     * <p>Si el usuario ya tiene {@code ROLE_PAGADO}, se le redirige directamente
     * al curso sin pasar por la pasarela.</p>
     *
     * @param auth  autenticación del usuario en sesión (puede ser {@code null} si no está autenticado)
     * @param model modelo Thymeleaf para pasar el precio formateado
     * @return vista {@code pagar} o redirección a {@code /curso}
     */
    @GetMapping("/pagar")
    public String mostrarPagina(Authentication auth, Model model) {
        // Si ya tiene acceso, redirigir directo al curso
        if (auth != null && auth.getAuthorities().stream()
                .anyMatch(a -> a.getAuthority().equals("ROLE_PAGADO"))) {
            return "redirect:/curso";
        }
        model.addAttribute("precio", String.format("%.2f", priceAmount / 100.0));
        return "pagar";
    }

    /**
     * Crea una sesión de pago en Stripe y redirige al usuario a la pasarela.
     *
     * <p>Utiliza el id del usuario como {@code clientReferenceId} para poder
     * identificarlo cuando llegue el webhook de confirmación.</p>
     *
     * @param auth    autenticación del usuario en sesión
     * @param request petición HTTP para construir las URLs de retorno
     * @return redirección a la URL de checkout de Stripe
     * @throws StripeException si falla la comunicación con la API de Stripe
     */
    @PostMapping("/pagar/iniciar")
    public String iniciarPago(Authentication auth, HttpServletRequest request) throws StripeException {
        String baseUrl = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();

        UserDetails userDetails = (UserDetails) auth.getPrincipal();
        var usuario = usuarioRepo.findByEmail(userDetails.getUsername()).orElseThrow();

        SessionCreateParams params = SessionCreateParams.builder()
                .setMode(SessionCreateParams.Mode.PAYMENT)
                .setSuccessUrl(baseUrl + "/pagar/exito?session_id={CHECKOUT_SESSION_ID}")
                .setCancelUrl(baseUrl + "/pagar/cancelado")
                .setClientReferenceId(String.valueOf(usuario.getId()))
                .setCustomerEmail(usuario.getEmail())
                .addLineItem(SessionCreateParams.LineItem.builder()
                        .setQuantity(1L)
                        .setPriceData(SessionCreateParams.LineItem.PriceData.builder()
                                .setCurrency(currency)
                                .setUnitAmount(priceAmount)
                                .setProductData(SessionCreateParams.LineItem.PriceData.ProductData.builder()
                                        .setName("Acceso completo al curso TAI – AGE")
                                        .setDescription("Acceso permanente a todos los temas, apuntes y actualizaciones")
                                        .build())
                                .build())
                        .build())
                .build();

        Session session = Session.create(params);
        return "redirect:" + session.getUrl();
    }

    /**
     * Página de confirmación mostrada tras un pago exitoso.
     *
     * <p>El acceso real al curso se concede mediante el webhook de Stripe,
     * no en esta página.</p>
     *
     * @return nombre de la plantilla {@code pago-exito}
     */
    @GetMapping("/pagar/exito")
    public String exitoPago() {
        return "pago-exito";
    }

    /**
     * Página mostrada cuando el usuario cancela el pago en Stripe.
     *
     * @return nombre de la plantilla {@code pago-cancelado}
     */
    @GetMapping("/pagar/cancelado")
    public String canceladoPago() {
        return "pago-cancelado";
    }
}
