package dev.lions.unionflow.server.resource;

import dev.lions.unionflow.server.api.dto.paiement.request.CreatePaiementRequest;
import dev.lions.unionflow.server.api.dto.paiement.response.PaiementResponse;
import dev.lions.unionflow.server.api.dto.paiement.response.PaiementSummaryResponse;
import dev.lions.unionflow.server.service.PaiementService;
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.tags.Tag;
import org.jboss.logging.Logger;

/**
 * Resource REST pour la gestion des paiements
 *
 * @author UnionFlow Team
 * @version 3.0
 * @since 2025-01-29
 */
@Path("/api/paiements")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@RolesAllowed({ "ADMIN", "ADMIN_ORGANISATION", "MEMBRE", "USER" })
@Tag(name = "Paiements", description = "Gestion des paiements : création, validation et suivi")
public class PaiementResource {

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

  @Inject
  PaiementService paiementService;

  /**
   * Crée un nouveau paiement
   *
   * @param request DTO du paiement à créer
   * @return Paiement créé
   */
  @POST
  @RolesAllowed({ "ADMIN", "ADMIN_ORGANISATION", "MEMBRE" })
  public Response creerPaiement(@Valid CreatePaiementRequest request) {
    LOG.infof("POST /api/paiements - Création paiement: %s", request.numeroReference());
    PaiementResponse result = paiementService.creerPaiement(request);
    return Response.status(Response.Status.CREATED).entity(result).build();
  }

  /**
   * Valide un paiement
   *
   * @param id ID du paiement
   * @return Paiement validé
   */
  @POST
  @RolesAllowed({ "ADMIN", "ADMIN_ORGANISATION", "MEMBRE" })
  @Path("/{id}/valider")
  public Response validerPaiement(@PathParam("id") UUID id) {
    LOG.infof("POST /api/paiements/%s/valider", id);
    PaiementResponse result = paiementService.validerPaiement(id);
    return Response.ok(result).build();
  }

  /**
   * Annule un paiement
   *
   * @param id ID du paiement
   * @return Paiement annulé
   */
  @POST
  @RolesAllowed({ "ADMIN", "ADMIN_ORGANISATION", "MEMBRE" })
  @Path("/{id}/annuler")
  public Response annulerPaiement(@PathParam("id") UUID id) {
    LOG.infof("POST /api/paiements/%s/annuler", id);
    PaiementResponse result = paiementService.annulerPaiement(id);
    return Response.ok(result).build();
  }

  /**
   * Trouve un paiement par son ID
   *
   * @param id ID du paiement
   * @return Paiement
   */
  @GET
  @Path("/{id}")
  public Response trouverParId(@PathParam("id") UUID id) {
    LOG.infof("GET /api/paiements/%s", id);
    PaiementResponse result = paiementService.trouverParId(id);
    return Response.ok(result).build();
  }

  /**
   * Trouve un paiement par son numéro de référence
   *
   * @param numeroReference Numéro de référence
   * @return Paiement
   */
  @GET
  @Path("/reference/{numeroReference}")
  public Response trouverParNumeroReference(@PathParam("numeroReference") String numeroReference) {
    LOG.infof("GET /api/paiements/reference/%s", numeroReference);
    PaiementResponse result = paiementService.trouverParNumeroReference(numeroReference);
    return Response.ok(result).build();
  }

  /**
   * Liste tous les paiements d'un membre
   *
   * @param membreId ID du membre
   * @return Liste des paiements
   */
  @GET
  @Path("/membre/{membreId}")
  public Response listerParMembre(@PathParam("membreId") UUID membreId) {
    LOG.infof("GET /api/paiements/membre/%s", membreId);
    List<PaiementSummaryResponse> result = paiementService.listerParMembre(membreId);
    return Response.ok(result).build();
  }

  /**
   * Liste l'historique des paiements du membre connecté (auto-détection).
   * Utilisé par la page personnelle "Payer mes Cotisations".
   *
   * @param limit Nombre maximum de paiements à retourner (défaut : 5)
   * @return Liste des derniers paiements
   */
  @GET
  @Path("/mes-paiements/historique")
  @RolesAllowed({ "MEMBRE", "ADMIN", "ADMIN_ORGANISATION" })
  public Response getMonHistoriquePaiements(
      @QueryParam("limit") @DefaultValue("5") int limit) {
    LOG.infof("GET /api/paiements/mes-paiements/historique?limit=%d", limit);
    List<PaiementSummaryResponse> result = paiementService.getMonHistoriquePaiements(limit);
    return Response.ok(result).build();
  }

  /**
   * Initie un paiement en ligne via un gateway (Wave, Orange Money, Free Money, Carte).
   * Retourne l'URL de redirection vers le gateway.
   *
   * @param request Données du paiement en ligne
   * @return URL de redirection + transaction ID
   */
  @POST
  @Path("/initier-paiement-en-ligne")
  @RolesAllowed({ "MEMBRE", "MEMBRE_ACTIF", "ADMIN", "ADMIN_ORGANISATION", "USER" })
  public Response initierPaiementEnLigne(@Valid dev.lions.unionflow.server.api.dto.paiement.request.InitierPaiementEnLigneRequest request) {
    LOG.infof("POST /api/paiements/initier-paiement-en-ligne - cotisation: %s, méthode: %s",
        request.cotisationId(), request.methodePaiement());
    dev.lions.unionflow.server.api.dto.paiement.response.PaiementGatewayResponse result =
        paiementService.initierPaiementEnLigne(request);
    return Response.status(Response.Status.CREATED).entity(result).build();
  }

  /**
   * Initie un dépôt sur compte épargne via Wave (même flux que cotisations).
   * Retourne wave_launch_url pour ouvrir l'app Wave puis retour deep link.
   */
  @POST
  @Path("/initier-depot-epargne-en-ligne")
  @RolesAllowed({ "MEMBRE", "MEMBRE_ACTIF", "ADMIN", "ADMIN_ORGANISATION", "USER" })
  public Response initierDepotEpargneEnLigne(@Valid dev.lions.unionflow.server.api.dto.paiement.request.InitierDepotEpargneRequest request) {
    LOG.infof("POST /api/paiements/initier-depot-epargne-en-ligne - compte: %s, montant: %s",
        request.compteId(), request.montant());
    dev.lions.unionflow.server.api.dto.paiement.response.PaiementGatewayResponse result =
        paiementService.initierDepotEpargneEnLigne(request);
    return Response.status(Response.Status.CREATED).entity(result).build();
  }

  /**
   * Polling du statut d'une IntentionPaiement Wave.
   * Si Wave a confirmé le paiement, réconcilie automatiquement la cotisation (PAYEE) et retourne COMPLETEE.
   * Le client web appelle cet endpoint toutes les 3 secondes pendant l'affichage du QR code.
   *
   * @param intentionId UUID de l'intention (clientReference retourné par initier-paiement-en-ligne)
   * @return Statut courant + waveLaunchUrl (pour re-générer le QR si besoin) + message
   */
  @GET
  @Path("/statut-intention/{intentionId}")
  @RolesAllowed({ "MEMBRE", "MEMBRE_ACTIF", "ADMIN", "ADMIN_ORGANISATION", "USER" })
  public Response getStatutIntention(@PathParam("intentionId") java.util.UUID intentionId) {
    LOG.infof("GET /api/paiements/statut-intention/%s", intentionId);
    dev.lions.unionflow.server.api.dto.paiement.response.IntentionStatutResponse result =
        paiementService.verifierStatutIntention(intentionId);
    return Response.ok(result).build();
  }

  /**
   * Déclare un paiement manuel (espèces, virement, chèque).
   * Le paiement est créé avec le statut EN_ATTENTE_VALIDATION.
   * Le trésorier devra le valider via une page admin.
   *
   * @param request Données du paiement manuel
   * @return Paiement créé (statut EN_ATTENTE_VALIDATION)
   */
  @POST
  @Path("/declarer-paiement-manuel")
  @RolesAllowed({ "MEMBRE", "ADMIN", "ADMIN_ORGANISATION" })
  public Response declarerPaiementManuel(@Valid dev.lions.unionflow.server.api.dto.paiement.request.DeclarerPaiementManuelRequest request) {
    LOG.infof("POST /api/paiements/declarer-paiement-manuel - cotisation: %s, méthode: %s",
        request.cotisationId(), request.methodePaiement());
    PaiementResponse result = paiementService.declarerPaiementManuel(request);
    return Response.status(Response.Status.CREATED).entity(result).build();
  }
}
