package dev.lions.unionflow.server.resource;

import dev.lions.unionflow.server.common.ErrorResponse;
import dev.lions.unionflow.server.api.dto.document.request.CreateDocumentRequest;
import dev.lions.unionflow.server.api.dto.document.response.DocumentResponse;
import dev.lions.unionflow.server.api.dto.document.request.CreatePieceJointeRequest;
import dev.lions.unionflow.server.api.dto.document.response.PieceJointeResponse;
import dev.lions.unionflow.server.service.DocumentService;
import dev.lions.unionflow.server.service.FileStorageService;
import dev.lions.unionflow.server.api.enums.document.TypeDocument;
import dev.lions.unionflow.server.entity.Document;
import dev.lions.unionflow.server.repository.DocumentRepository;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Inject;
import org.jboss.resteasy.reactive.multipart.FileUpload;
import jakarta.validation.Valid;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.nio.file.Files;
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 documentaire
 *
 * @author UnionFlow Team
 * @version 3.0
 * @since 2025-01-29
 */
@Path("/api/documents")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@RolesAllowed({ "ADMIN", "ADMIN_ORGANISATION", "MEMBRE", "USER" })
@Tag(name = "Documents", description = "Gestion documentaire : documents et pièces jointes")
public class DocumentResource {

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

  @Inject
  DocumentService documentService;

  @Inject
  FileStorageService fileStorageService;

  @Inject
  DocumentRepository documentRepository;

  /**
   * Crée un nouveau document
   *
   * @param documentDTO DTO du document à créer
   * @return Document créé
   */
  @POST
  @RolesAllowed({ "ADMIN", "ADMIN_ORGANISATION", "MEMBRE" })
  public Response creerDocument(@Valid CreateDocumentRequest request) {
    try {
      DocumentResponse result = documentService.creerDocument(request);
      return Response.status(Response.Status.CREATED).entity(result).build();
    } catch (Exception e) {
      LOG.errorf(e, "Erreur lors de la création du document");
      return Response.status(Response.Status.BAD_REQUEST)
          .entity(ErrorResponse.ofError("Erreur lors de la création du document: " + e.getMessage()))
          .build();
    }
  }

  /**
   * Upload un fichier (image ou PDF) pour justificatif LCB-FT
   *
   * @param file Fichier uploadé
   * @param description Description optionnelle
   * @return ID du document créé
   */
  @POST
  @Path("/upload")
  @Consumes(MediaType.MULTIPART_FORM_DATA)
  @RolesAllowed({ "ADMIN", "ADMIN_ORGANISATION", "MEMBRE" })
  @jakarta.transaction.Transactional
  public Response uploadFile(
      @org.jboss.resteasy.reactive.RestForm("file") FileUpload file,
      @org.jboss.resteasy.reactive.RestForm("description") String description,
      @org.jboss.resteasy.reactive.RestForm("typeDocument") String typeDocument
  ) {
    try {
      if (file == null || file.fileName() == null) {
        return Response.status(Response.Status.BAD_REQUEST)
            .entity(ErrorResponse.ofError("Aucun fichier fourni"))
            .build();
      }

      LOG.infof("Upload de fichier: %s (%d octets, type: %s)",
          file.fileName(), file.size(), file.contentType());

      // Stocker le fichier physiquement
      FileStorageService.FileMetadata metadata;
      try (var inputStream = Files.newInputStream(file.filePath())) {
        metadata = fileStorageService.storeFile(
            inputStream,
            file.fileName(),
            file.contentType(),
            file.size()
        );
      }

      // Créer l'entité Document en BDD
      Document document = Document.builder()
          .nomFichier(metadata.getNomFichier())
          .nomOriginal(metadata.getNomOriginal())
          .cheminStockage(metadata.getCheminStockage())
          .typeMime(metadata.getTypeMime())
          .tailleOctets(metadata.getTailleOctets())
          .hashMd5(metadata.getHashMd5())
          .hashSha256(metadata.getHashSha256())
          .description(description)
          .typeDocument(typeDocument != null ? TypeDocument.valueOf(typeDocument) : TypeDocument.PIECE_JUSTIFICATIVE)
          .build();

      documentRepository.persist(document);

      LOG.infof("Document créé avec ID: %s", document.getId());

      // Retourner l'ID du document (pour référencer dans TransactionEpargneRequest)
      return Response.status(Response.Status.CREATED)
          .entity(java.util.Map.of(
              "id", document.getId().toString(),
              "nomFichier", document.getNomFichier(),
              "taille", document.getTailleFormatee(),
              "typeMime", document.getTypeMime()
          ))
          .build();

    } catch (IllegalArgumentException e) {
      LOG.warnf("Validation échouée pour upload: %s", e.getMessage());
      return Response.status(Response.Status.BAD_REQUEST)
          .entity(ErrorResponse.ofError(e.getMessage()))
          .build();
    } catch (Exception e) {
      LOG.errorf(e, "Erreur lors de l'upload du fichier");
      return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
          .entity(ErrorResponse.ofError("Erreur lors de l'upload: " + e.getMessage()))
          .build();
    }
  }

  /**
   * Liste les documents de l'utilisateur connecté
   *
   * @return Liste des documents du membre connecté
   */
  @GET
  @Path("/mes-documents")
  public Response listerMesDocuments() {
    try {
      List<DocumentResponse> result = documentService.listerMesDocuments();
      return Response.ok(result).build();
    } catch (Exception e) {
      LOG.errorf(e, "Erreur lors de la liste des documents du membre connecté");
      return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
          .entity(ErrorResponse.ofError("Erreur lors de la récupération des documents: " + e.getMessage()))
          .build();
    }
  }

  /**
   * Trouve un document par son ID
   *
   * @param id ID du document
   * @return Document
   */
  @GET
  @Path("/{id}")
  public Response trouverParId(@PathParam("id") UUID id) {
    try {
      DocumentResponse result = documentService.trouverParId(id);
      return Response.ok(result).build();
    } catch (jakarta.ws.rs.NotFoundException e) {
      return Response.status(Response.Status.NOT_FOUND)
          .entity(ErrorResponse.ofError("Document non trouvé"))
          .build();
    } catch (Exception e) {
      LOG.errorf(e, "Erreur lors de la recherche du document");
      return Response.status(Response.Status.BAD_REQUEST)
          .entity(ErrorResponse.ofError("Erreur lors de la recherche du document: " + e.getMessage()))
          .build();
    }
  }

  /**
   * Enregistre un téléchargement de document
   *
   * @param id ID du document
   * @return Succès
   */
  @POST
  @RolesAllowed({ "ADMIN", "ADMIN_ORGANISATION", "MEMBRE" })
  @Path("/{id}/telechargement")
  public Response enregistrerTelechargement(@PathParam("id") UUID id) {
    try {
      documentService.enregistrerTelechargement(id);
      return Response.ok().build();
    } catch (jakarta.ws.rs.NotFoundException e) {
      return Response.status(Response.Status.NOT_FOUND)
          .entity(ErrorResponse.ofError("Document non trouvé"))
          .build();
    } catch (Exception e) {
      LOG.errorf(e, "Erreur lors de l'enregistrement du téléchargement");
      return Response.status(Response.Status.BAD_REQUEST)
          .entity(ErrorResponse.ofError("Erreur lors de l'enregistrement du téléchargement: " + e.getMessage()))
          .build();
    }
  }

  /**
   * Crée une pièce jointe
   *
   * @param pieceJointeDTO DTO de la pièce jointe à créer
   * @return Pièce jointe créée
   */
  @POST
  @RolesAllowed({ "ADMIN", "ADMIN_ORGANISATION", "MEMBRE" })
  @Path("/pieces-jointes")
  public Response creerPieceJointe(@Valid CreatePieceJointeRequest request) {
    try {
      PieceJointeResponse result = documentService.creerPieceJointe(request);
      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 de la pièce jointe");
      return Response.status(Response.Status.BAD_REQUEST)
          .entity(ErrorResponse.ofError("Erreur lors de la création de la pièce jointe: " + e.getMessage()))
          .build();
    }
  }

  /**
   * Liste toutes les pièces jointes d'un document
   *
   * @param documentId ID du document
   * @return Liste des pièces jointes
   */
  @GET
  @Path("/{documentId}/pieces-jointes")
  public Response listerPiecesJointesParDocument(@PathParam("documentId") UUID documentId) {
    try {
      List<PieceJointeResponse> result = documentService.listerPiecesJointesParDocument(documentId);
      return Response.ok(result).build();
    } catch (Exception e) {
      LOG.errorf(e, "Erreur lors de la liste des pièces jointes");
      return Response.status(Response.Status.BAD_REQUEST)
          .entity(ErrorResponse.ofError("Erreur lors de la liste des pièces jointes: " + e.getMessage()))
          .build();
    }
  }

}

