package dev.lions.unionflow.server.resource;

import dev.lions.unionflow.server.api.dto.paiement.WaveBalanceDTO;
import dev.lions.unionflow.server.api.dto.paiement.WaveCheckoutSessionDTO;
import dev.lions.unionflow.server.api.dto.paiement.WaveWebhookDTO;
import dev.lions.unionflow.server.service.WaveService;
import jakarta.inject.Inject;
import jakarta.validation.Valid;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.media.Content;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.jboss.logging.Logger;

/**
 * Resource REST pour l'intégration Wave Money
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2025-01-17
 */
@Path("/api/wave")
@Tag(name = "Wave Money", description = "API d'intégration Wave Money pour les paiements")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class WaveResource {

  private static final Logger LOG = Logger.getLogger(WaveResource.class);

  @Inject WaveService waveService;

  @POST
  @Path("/checkout/sessions")
  @Operation(
      summary = "Créer une session de paiement Wave",
      description = "Crée une nouvelle session de paiement via l'API Wave Checkout")
  @APIResponse(
      responseCode = "200",
      description = "Session créée avec succès",
      content =
          @Content(
              mediaType = MediaType.APPLICATION_JSON,
              schema = @Schema(implementation = WaveCheckoutSessionDTO.class)))
  @APIResponse(responseCode = "400", description = "Données invalides")
  @APIResponse(responseCode = "500", description = "Erreur serveur")
  public Response creerSessionPaiement(
      @Parameter(description = "Montant à payer", required = true) @QueryParam("montant")
          @NotNull
          @DecimalMin("0.01")
          BigDecimal montant,
      @Parameter(description = "Devise (XOF par défaut)") @QueryParam("devise") String devise,
      @Parameter(description = "URL de succès", required = true) @QueryParam("successUrl")
          @NotBlank
          String successUrl,
      @Parameter(description = "URL d'erreur", required = true) @QueryParam("errorUrl")
          @NotBlank
          String errorUrl,
      @Parameter(description = "Référence UnionFlow") @QueryParam("reference")
          String referenceUnionFlow,
      @Parameter(description = "Description du paiement") @QueryParam("description")
          String description,
      @Parameter(description = "ID de l'organisation") @QueryParam("organisationId") UUID organisationId,
      @Parameter(description = "ID du membre") @QueryParam("membreId") UUID membreId) {
    try {
      WaveCheckoutSessionDTO session =
          waveService.creerSessionPaiement(
              montant,
              devise,
              successUrl,
              errorUrl,
              referenceUnionFlow,
              description,
              organisationId,
              membreId);

      return Response.ok(session).build();

    } catch (Exception e) {
      LOG.errorf(e, "Erreur lors de la création de la session: %s", e.getMessage());
      Map<String, String> erreur = new HashMap<>();
      erreur.put("erreur", "Erreur lors de la création de la session");
      erreur.put("message", e.getMessage());
      return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(erreur).build();
    }
  }

  @GET
  @Path("/checkout/sessions/{sessionId}")
  @Operation(
      summary = "Vérifier le statut d'une session",
      description = "Récupère le statut d'une session de paiement Wave")
  @APIResponse(
      responseCode = "200",
      description = "Statut récupéré avec succès",
      content =
          @Content(
              mediaType = MediaType.APPLICATION_JSON,
              schema = @Schema(implementation = WaveCheckoutSessionDTO.class)))
  @APIResponse(responseCode = "404", description = "Session non trouvée")
  public Response verifierStatutSession(
      @Parameter(description = "ID de la session Wave", required = true) @PathParam("sessionId")
          @NotBlank
          String sessionId) {
    try {
      WaveCheckoutSessionDTO session = waveService.verifierStatutSession(sessionId);
      return Response.ok(session).build();

    } catch (Exception e) {
      LOG.errorf(e, "Erreur lors de la vérification du statut: %s", e.getMessage());
      Map<String, String> erreur = new HashMap<>();
      erreur.put("erreur", "Erreur lors de la vérification du statut");
      erreur.put("message", e.getMessage());
      return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(erreur).build();
    }
  }

  @POST
  @Path("/webhooks")
  @Operation(
      summary = "Recevoir un webhook Wave",
      description = "Endpoint pour recevoir les notifications webhook de Wave")
  @APIResponse(
      responseCode = "200",
      description = "Webhook reçu et traité",
      content =
          @Content(
              mediaType = MediaType.APPLICATION_JSON,
              schema = @Schema(implementation = WaveWebhookDTO.class)))
  @APIResponse(responseCode = "400", description = "Webhook invalide")
  @APIResponse(responseCode = "401", description = "Signature invalide")
  @Consumes(MediaType.APPLICATION_JSON)
  public Response recevoirWebhook(
      @Parameter(description = "Payload du webhook", required = true) String payload,
      @jakarta.ws.rs.HeaderParam("X-Wave-Signature") String signature) {
    try {
      // Récupérer les headers
      Map<String, String> headers = new HashMap<>();
      if (signature != null) {
        headers.put("X-Wave-Signature", signature);
      }

      WaveWebhookDTO webhook = waveService.traiterWebhook(payload, signature, headers);
      return Response.ok(webhook).build();

    } catch (SecurityException e) {
      LOG.warnf("Signature webhook invalide: %s", e.getMessage());
      return Response.status(Response.Status.UNAUTHORIZED).build();

    } catch (Exception e) {
      LOG.errorf(e, "Erreur lors du traitement du webhook: %s", e.getMessage());
      Map<String, String> erreur = new HashMap<>();
      erreur.put("erreur", "Erreur lors du traitement du webhook");
      erreur.put("message", e.getMessage());
      return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(erreur).build();
    }
  }

  @GET
  @Path("/balance")
  @Operation(
      summary = "Consulter le solde Wave",
      description = "Récupère le solde disponible du wallet Wave")
  @APIResponse(
      responseCode = "200",
      description = "Solde récupéré avec succès",
      content =
          @Content(
              mediaType = MediaType.APPLICATION_JSON,
              schema = @Schema(implementation = WaveBalanceDTO.class)))
  public Response consulterSolde() {
    try {
      WaveBalanceDTO balance = waveService.consulterSolde();
      return Response.ok(balance).build();

    } catch (Exception e) {
      LOG.errorf(e, "Erreur lors de la consultation du solde: %s", e.getMessage());
      Map<String, String> erreur = new HashMap<>();
      erreur.put("erreur", "Erreur lors de la consultation du solde");
      erreur.put("message", e.getMessage());
      return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(erreur).build();
    }
  }

  @GET
  @Path("/test")
  @Operation(
      summary = "Tester la connexion Wave",
      description = "Teste la connexion et la configuration de l'API Wave")
  @APIResponse(responseCode = "200", description = "Test effectué")
  public Response testerConnexion() {
    Map<String, Object> resultat = waveService.testerConnexion();
    return Response.ok(resultat).build();
  }
}

