package dev.lions.unionflow.server.service;

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.entity.*;
import dev.lions.unionflow.server.repository.*;
import dev.lions.unionflow.server.service.KeycloakService;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.NotFoundException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import org.jboss.logging.Logger;

/**
 * Service métier pour la gestion documentaire
 *
 * @author UnionFlow Team
 * @version 3.0
 * @since 2025-01-29
 */
@ApplicationScoped
public class DocumentService {

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

  @Inject
  DocumentRepository documentRepository;

  @Inject
  PieceJointeRepository pieceJointeRepository;

  @Inject
  MembreRepository membreRepository;

  @Inject
  OrganisationRepository organisationRepository;

  @Inject
  KeycloakService keycloakService;

  /**
   * Crée un nouveau document
   *
   * @param documentDTO DTO du document à créer
   * @return DTO du document créé
   */
  @Transactional
  public DocumentResponse creerDocument(CreateDocumentRequest request) {
    LOG.infof("Création d'un nouveau document: %s", request.nomFichier());

    Document document = convertToEntity(request);
    document.setCreePar(keycloakService.getCurrentUserEmail());

    documentRepository.persist(document);
    LOG.infof("Document créé avec succès: ID=%s, Fichier=%s", document.getId(), document.getNomFichier());

    return convertToResponse(document);
  }

  /**
   * Trouve un document par son ID
   *
   * @param id ID du document
   * @return DTO du document
   */
  public DocumentResponse trouverParId(UUID id) {
    return documentRepository
        .findDocumentById(id)
        .map(this::convertToResponse)
        .orElseThrow(() -> new NotFoundException("Document non trouvé avec l'ID: " + id));
  }

  /**
   * Enregistre un téléchargement de document
   *
   * @param id ID du document
   */
  @Transactional
  public void enregistrerTelechargement(UUID id) {
    Document document = documentRepository
        .findDocumentById(id)
        .orElseThrow(() -> new NotFoundException("Document non trouvé avec l'ID: " + id));

    document.setNombreTelechargements(document.getNombreTelechargements() + 1);
    document.setDateDernierTelechargement(LocalDateTime.now());
    document.setModifiePar(keycloakService.getCurrentUserEmail());

    documentRepository.persist(document);
  }

  /**
   * Crée une pièce jointe
   *
   * @param pieceJointeDTO DTO de la pièce jointe à créer
   * @return DTO de la pièce jointe créée
   */
  @Transactional
  public PieceJointeResponse creerPieceJointe(CreatePieceJointeRequest request) {
    LOG.infof("Création d'une nouvelle pièce jointe");

    PieceJointe pieceJointe = convertToEntity(request);

    // Validation polymorphique
    if (pieceJointe.getTypeEntiteRattachee() == null
        || pieceJointe.getTypeEntiteRattachee().isBlank()
        || pieceJointe.getEntiteRattacheeId() == null) {
      throw new IllegalArgumentException(
          "type_entite_rattachee et entite_rattachee_id"
              + " sont obligatoires");
    }

    pieceJointe.setCreePar(keycloakService.getCurrentUserEmail());
    pieceJointeRepository.persist(pieceJointe);

    LOG.infof("Pièce jointe créée avec succès: ID=%s", pieceJointe.getId());
    return convertToResponse(pieceJointe);
  }

  /**
   * Liste les documents de l'utilisateur connecté
   *
   * @return Liste des documents créés par l'utilisateur connecté
   */
  public List<DocumentResponse> listerMesDocuments() {
    String email = keycloakService.getCurrentUserEmail();
    LOG.infof("Listing des documents pour l'utilisateur: %s", email);
    return documentRepository.findByCreePar(email).stream()
        .map(this::convertToResponse)
        .collect(Collectors.toList());
  }

  /**
   * Liste toutes les pièces jointes d'un document
   *
   * @param documentId ID du document
   * @return Liste des pièces jointes
   */
  public List<PieceJointeResponse> listerPiecesJointesParDocument(UUID documentId) {
    return pieceJointeRepository.findByDocumentId(documentId).stream()
        .map(this::convertToResponse)
        .collect(Collectors.toList());
  }

  // ========================================
  // MÉTHODES PRIVÉES
  // ========================================

  /** Convertit une entité Document en DTO */
  private DocumentResponse convertToResponse(Document document) {
    if (document == null) {
      return null;
    }

    DocumentResponse dto = new DocumentResponse();
    dto.setId(document.getId());
    dto.setNomFichier(document.getNomFichier());
    dto.setNomOriginal(document.getNomOriginal());
    dto.setCheminStockage(document.getCheminStockage());
    dto.setTypeMime(document.getTypeMime());
    dto.setTailleOctets(document.getTailleOctets());
    dto.setTypeDocument(document.getTypeDocument());
    dto.setHashMd5(document.getHashMd5());
    dto.setHashSha256(document.getHashSha256());
    dto.setDescription(document.getDescription());
    dto.setNombreTelechargements(document.getNombreTelechargements());
    dto.setTailleFormatee(document.getTailleFormatee());
    dto.setDateCreation(document.getDateCreation());
    dto.setDateModification(document.getDateModification());
    dto.setActif(document.getActif());

    return dto;
  }

  /** Convertit un DTO en entité Document */
  private Document convertToEntity(CreateDocumentRequest dto) {
    if (dto == null) {
      return null;
    }

    Document document = new Document();
    document.setNomFichier(dto.nomFichier());
    document.setNomOriginal(dto.nomOriginal());
    document.setCheminStockage(dto.cheminStockage());
    document.setTypeMime(dto.typeMime());
    document.setTailleOctets(dto.tailleOctets());
    document.setTypeDocument(dto.typeDocument() != null ? dto.typeDocument()
        : dev.lions.unionflow.server.api.enums.document.TypeDocument.AUTRE);
    document.setHashMd5(dto.hashMd5());
    document.setHashSha256(dto.hashSha256());
    document.setDescription(dto.description());

    return document;
  }

  /** Convertit une entité PieceJointe en DTO */
  private PieceJointeResponse convertToResponse(PieceJointe pj) {
    if (pj == null) {
      return null;
    }

    PieceJointeResponse dto = new PieceJointeResponse();
    dto.setId(pj.getId());
    dto.setOrdre(pj.getOrdre());
    dto.setLibelle(pj.getLibelle());
    dto.setCommentaire(pj.getCommentaire());

    if (pj.getDocument() != null) {
      dto.setDocumentId(pj.getDocument().getId());
    }
    dto.setTypeEntiteRattachee(
        pj.getTypeEntiteRattachee());
    dto.setEntiteRattacheeId(
        pj.getEntiteRattacheeId());

    dto.setDateCreation(pj.getDateCreation());
    dto.setDateModification(
        pj.getDateModification());
    dto.setActif(pj.getActif());

    return dto;
  }

  /** Convertit un DTO en entité PieceJointe */
  private PieceJointe convertToEntity(
      CreatePieceJointeRequest dto) {
    if (dto == null) {
      return null;
    }

    PieceJointe pj = new PieceJointe();
    pj.setOrdre(
        dto.ordre() != null ? dto.ordre() : 1);
    pj.setLibelle(dto.libelle());
    pj.setCommentaire(dto.commentaire());

    // Document (obligatoire)
    if (dto.documentId() != null) {
      Document document = documentRepository
          .findDocumentById(dto.documentId())
          .orElseThrow(
              () -> new NotFoundException(
                  "Document non trouvé: "
                      + dto.documentId()));
      pj.setDocument(document);
    }

    // Rattachement polymorphique
    pj.setTypeEntiteRattachee(
        dto.typeEntiteRattachee());
    pj.setEntiteRattacheeId(
        dto.entiteRattacheeId());

    return pj;
  }
}
