package dev.lions.unionflow.server.resource;

import dev.lions.unionflow.server.common.ErrorResponse;
import dev.lions.unionflow.server.api.dto.wave.CompteWaveDTO;
import dev.lions.unionflow.server.api.dto.wave.TransactionWaveDTO;
import dev.lions.unionflow.server.api.enums.wave.StatutTransactionWave;
import dev.lions.unionflow.server.service.WaveService;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Inject;
import jakarta.validation.Valid;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.util.List;
import java.util.UUID;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.jboss.logging.Logger;

/**
 * Resource REST pour l'intégration Wave Mobile Money
 *
 * @author UnionFlow Team
 * @version 3.0
 * @since 2025-01-29
 */
@Path("/api/wave")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@RolesAllowed({ "ADMIN", "ADMIN_ORGANISATION", "MEMBRE", "USER" })
@Tag(name = "Wave Mobile Money", description = "Gestion des comptes et transactions Wave Mobile Money")
public class WaveResource {

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

  @Inject
  WaveService waveService;

  // ========================================
  // COMPTES WAVE
  // ========================================

  @POST
  @RolesAllowed({ "ADMIN", "ADMIN_ORGANISATION", "MEMBRE" })
  @Path("/comptes")
  @Operation(summary = "Créer un compte Wave", description = "Crée un nouveau compte Wave pour un membre ou une organisation")
  @APIResponses({
      @APIResponse(responseCode = "201", description = "Compte Wave créé avec succès"),
      @APIResponse(responseCode = "400", description = "Données invalides")
  })
  public Response creerCompteWave(@Valid CompteWaveDTO compteWaveDTO) {
    try {
      CompteWaveDTO result = waveService.creerCompteWave(compteWaveDTO);
      return Response.status(Response.Status.CREATED).entity(result).build();
    } catch (IllegalArgumentException e) {
      return Response.status(Response.Status.BAD_REQUEST)
          .entity(ErrorResponse.ofError(e.getMessage()))
          .build();
    } catch (Exception e) {
      LOG.errorf(e, "Erreur lors de la création du compte Wave");
      return Response.status(Response.Status.BAD_REQUEST)
          .entity(ErrorResponse.ofError("Erreur lors de la création du compte Wave: " + e.getMessage()))
          .build();
    }
  }

  @PUT
  @RolesAllowed({ "ADMIN", "ADMIN_ORGANISATION", "MEMBRE" })
  @Path("/comptes/{id}")
  @Operation(summary = "Mettre à jour un compte Wave", description = "Met à jour les informations d'un compte Wave existant")
  @APIResponses({
      @APIResponse(responseCode = "200", description = "Compte Wave mis à jour"),
      @APIResponse(responseCode = "404", description = "Compte Wave non trouvé"),
      @APIResponse(responseCode = "400", description = "Données invalides")
  })
  public Response mettreAJourCompteWave(
      @Parameter(description = "UUID du compte Wave", required = true) @PathParam("id") UUID id,
      @Valid CompteWaveDTO compteWaveDTO) {
    try {
      CompteWaveDTO result = waveService.mettreAJourCompteWave(id, compteWaveDTO);
      return Response.ok(result).build();
    } catch (jakarta.ws.rs.NotFoundException e) {
      return Response.status(Response.Status.NOT_FOUND)
          .entity(ErrorResponse.ofError("Compte Wave non trouvé"))
          .build();
    } catch (Exception e) {
      LOG.errorf(e, "Erreur lors de la mise à jour du compte Wave");
      return Response.status(Response.Status.BAD_REQUEST)
          .entity(ErrorResponse.ofError("Erreur lors de la mise à jour du compte Wave: " + e.getMessage()))
          .build();
    }
  }

  @POST
  @RolesAllowed({ "ADMIN", "ADMIN_ORGANISATION", "MEMBRE" })
  @Path("/comptes/{id}/verifier")
  @Operation(summary = "Vérifier un compte Wave", description = "Vérifie la validité d'un compte Wave")
  @APIResponses({
      @APIResponse(responseCode = "200", description = "Compte Wave vérifié"),
      @APIResponse(responseCode = "404", description = "Compte Wave non trouvé"),
      @APIResponse(responseCode = "400", description = "Erreur de vérification")
  })
  public Response verifierCompteWave(
      @Parameter(description = "UUID du compte Wave", required = true) @PathParam("id") UUID id) {
    try {
      CompteWaveDTO result = waveService.verifierCompteWave(id);
      return Response.ok(result).build();
    } catch (jakarta.ws.rs.NotFoundException e) {
      return Response.status(Response.Status.NOT_FOUND)
          .entity(ErrorResponse.ofError("Compte Wave non trouvé"))
          .build();
    } catch (Exception e) {
      LOG.errorf(e, "Erreur lors de la vérification du compte Wave");
      return Response.status(Response.Status.BAD_REQUEST)
          .entity(ErrorResponse.ofError("Erreur lors de la vérification du compte Wave: " + e.getMessage()))
          .build();
    }
  }

  @GET
  @Path("/comptes/{id}")
  @Operation(summary = "Trouver un compte Wave par ID", description = "Recherche un compte Wave par son identifiant unique")
  @APIResponses({
      @APIResponse(responseCode = "200", description = "Compte Wave trouvé"),
      @APIResponse(responseCode = "404", description = "Compte Wave non trouvé")
  })
  public Response trouverCompteWaveParId(
      @Parameter(description = "UUID du compte Wave", required = true) @PathParam("id") UUID id) {
    try {
      CompteWaveDTO result = waveService.trouverCompteWaveParId(id);
      return Response.ok(result).build();
    } catch (jakarta.ws.rs.NotFoundException e) {
      return Response.status(Response.Status.NOT_FOUND)
          .entity(ErrorResponse.ofError("Compte Wave non trouvé"))
          .build();
    } catch (Exception e) {
      LOG.errorf(e, "Erreur lors de la recherche du compte Wave");
      return Response.status(Response.Status.BAD_REQUEST)
          .entity(ErrorResponse.ofError("Erreur lors de la recherche du compte Wave: " + e.getMessage()))
          .build();
    }
  }

  @GET
  @Path("/comptes/telephone/{numeroTelephone}")
  @Operation(summary = "Trouver un compte Wave par téléphone", description = "Recherche un compte Wave par numéro de téléphone")
  @APIResponses({
      @APIResponse(responseCode = "200", description = "Compte Wave trouvé"),
      @APIResponse(responseCode = "404", description = "Compte Wave non trouvé pour ce numéro")
  })
  public Response trouverCompteWaveParTelephone(
      @Parameter(description = "Numéro de téléphone associé au compte Wave", required = true) @PathParam("numeroTelephone") String numeroTelephone) {
    try {
      CompteWaveDTO result = waveService.trouverCompteWaveParTelephone(numeroTelephone);
      if (result == null) {
        return Response.status(Response.Status.NOT_FOUND)
            .entity(ErrorResponse.ofError("Compte Wave non trouvé"))
            .build();
      }
      return Response.ok(result).build();
    } catch (Exception e) {
      LOG.errorf(e, "Erreur lors de la recherche du compte Wave");
      return Response.status(Response.Status.BAD_REQUEST)
          .entity(ErrorResponse.ofError("Erreur lors de la recherche du compte Wave: " + e.getMessage()))
          .build();
    }
  }

  @GET
  @Path("/comptes/organisation/{organisationId}")
  @Operation(summary = "Lister les comptes Wave d'une organisation", description = "Retourne tous les comptes Wave associés à une organisation")
  @APIResponses({
      @APIResponse(responseCode = "200", description = "Liste des comptes Wave"),
      @APIResponse(responseCode = "400", description = "Erreur lors de la récupération")
  })
  public Response listerComptesWaveParOrganisation(
      @Parameter(description = "UUID de l'organisation", required = true) @PathParam("organisationId") UUID organisationId) {
    try {
      List<CompteWaveDTO> result = waveService.listerComptesWaveParOrganisation(organisationId);
      return Response.ok(result).build();
    } catch (Exception e) {
      LOG.errorf(e, "Erreur lors de la liste des comptes Wave");
      return Response.status(Response.Status.BAD_REQUEST)
          .entity(ErrorResponse.ofError("Erreur lors de la liste des comptes Wave: " + e.getMessage()))
          .build();
    }
  }

  // ========================================
  // TRANSACTIONS WAVE
  // ========================================

  @POST
  @RolesAllowed({ "ADMIN", "ADMIN_ORGANISATION", "MEMBRE" })
  @Path("/transactions")
  @Operation(summary = "Créer une transaction Wave", description = "Initie une nouvelle transaction de paiement Wave")
  @APIResponses({
      @APIResponse(responseCode = "201", description = "Transaction Wave créée"),
      @APIResponse(responseCode = "400", description = "Données invalides ou erreur de traitement")
  })
  public Response creerTransactionWave(@Valid TransactionWaveDTO transactionWaveDTO) {
    try {
      TransactionWaveDTO result = waveService.creerTransactionWave(transactionWaveDTO);
      return Response.status(Response.Status.CREATED).entity(result).build();
    } catch (Exception e) {
      LOG.errorf(e, "Erreur lors de la création de la transaction Wave");
      return Response.status(Response.Status.BAD_REQUEST)
          .entity(ErrorResponse.ofError("Erreur lors de la création de la transaction Wave: " + e.getMessage()))
          .build();
    }
  }

  @PUT
  @RolesAllowed({ "ADMIN", "ADMIN_ORGANISATION", "MEMBRE" })
  @Path("/transactions/{waveTransactionId}/statut")
  @Operation(summary = "Mettre à jour le statut d'une transaction", description = "Met à jour le statut d'une transaction Wave (ex: COMPLETED, FAILED)")
  @APIResponses({
      @APIResponse(responseCode = "200", description = "Statut mis à jour"),
      @APIResponse(responseCode = "404", description = "Transaction non trouvée"),
      @APIResponse(responseCode = "400", description = "Erreur de mise à jour")
  })
  public Response mettreAJourStatutTransaction(
      @Parameter(description = "Identifiant Wave de la transaction", required = true) @PathParam("waveTransactionId") String waveTransactionId,
      StatutTransactionWave statut) {
    try {
      TransactionWaveDTO result = waveService.mettreAJourStatutTransaction(waveTransactionId, statut);
      return Response.ok(result).build();
    } catch (jakarta.ws.rs.NotFoundException e) {
      return Response.status(Response.Status.NOT_FOUND)
          .entity(ErrorResponse.ofError("Transaction Wave non trouvée"))
          .build();
    } catch (Exception e) {
      LOG.errorf(e, "Erreur lors de la mise à jour du statut de la transaction Wave");
      return Response.status(Response.Status.BAD_REQUEST)
          .entity(ErrorResponse.ofError("Erreur lors de la mise à jour du statut de la transaction Wave: " + e.getMessage()))
          .build();
    }
  }

  @GET
  @Path("/transactions/{waveTransactionId}")
  @Operation(summary = "Trouver une transaction Wave", description = "Recherche une transaction Wave par son identifiant Wave")
  @APIResponses({
      @APIResponse(responseCode = "200", description = "Transaction trouvée"),
      @APIResponse(responseCode = "404", description = "Transaction non trouvée")
  })
  public Response trouverTransactionWaveParId(
      @Parameter(description = "Identifiant Wave de la transaction", required = true) @PathParam("waveTransactionId") String waveTransactionId) {
    try {
      TransactionWaveDTO result = waveService.trouverTransactionWaveParId(waveTransactionId);
      return Response.ok(result).build();
    } catch (jakarta.ws.rs.NotFoundException e) {
      return Response.status(Response.Status.NOT_FOUND)
          .entity(ErrorResponse.ofError("Transaction Wave non trouvée"))
          .build();
    } catch (Exception e) {
      LOG.errorf(e, "Erreur lors de la recherche de la transaction Wave");
      return Response.status(Response.Status.BAD_REQUEST)
          .entity(ErrorResponse.ofError("Erreur lors de la recherche de la transaction Wave: " + e.getMessage()))
          .build();
    }
  }

}

