package dev.lions.unionflow.server.entity;

import dev.lions.unionflow.server.api.enums.messagerie.TypeContenu;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.PrePersist;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

/**
 * Message envoyé dans une conversation.
 *
 * <p>Supporte trois types de contenu :
 * <ul>
 *   <li>{@link TypeContenu#TEXTE} — message texte classique</li>
 *   <li>{@link TypeContenu#VOCAL} — note vocale (Opus/AAC), stockée sur object storage.
 *       Champs {@code urlFichier} + {@code dureeAudio} obligatoires.</li>
 *   <li>{@link TypeContenu#IMAGE} — image JPEG/PNG. Champ {@code urlFichier} obligatoire.</li>
 * </ul>
 *
 * <p>La suppression est douce : {@code supprimeLe} est renseigné au lieu de
 * supprimer la ligne. Le contenu devient {@code "[Message supprimé]"}.
 *
 * <p>Table : {@code messages}
 *
 * @author UnionFlow Team
 * @version 4.0
 * @since 2026-04-13
 */
@Entity
@Table(
    name = "messages",
    indexes = {
        @Index(name = "idx_messages_conversation",  columnList = "conversation_id"),
        @Index(name = "idx_messages_expediteur",    columnList = "expediteur_id"),
        @Index(name = "idx_messages_date_creation", columnList = "date_creation"),
        @Index(name = "idx_messages_parent",        columnList = "message_parent_id")
    }
)
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@EqualsAndHashCode(callSuper = true)
public class Message extends BaseEntity {

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "conversation_id", nullable = false)
    private Conversation conversation;

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "expediteur_id", nullable = false)
    private Membre expediteur;

    @Enumerated(EnumType.STRING)
    @Builder.Default
    @Column(name = "type_message", nullable = false, length = 20)
    private TypeContenu typeMessage = TypeContenu.TEXTE;

    /** Texte du message — null pour les vocaux/images. */
    @Column(name = "contenu", columnDefinition = "TEXT")
    private String contenu;

    /**
     * URL du fichier audio (notes vocales) ou image.
     * Format : https://storage.lions.dev/chat/{conversationId}/{messageId}.opus
     */
    @Column(name = "url_fichier", length = 500)
    private String urlFichier;

    /** Durée en secondes pour les notes vocales. */
    @Column(name = "duree_audio")
    private Integer dureeAudio;

    /**
     * Transcription automatique du vocal — null en V1.
     * Sera renseigné par un service Speech-to-Text en V2.
     */
    @Column(name = "transcription", columnDefinition = "TEXT")
    private String transcription;

    /** Message auquel celui-ci répond (threading léger). */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "message_parent_id")
    private Message messageParent;

    /** Date de suppression douce (null = message actif). */
    @Column(name = "supprime_le")
    private LocalDateTime supprimeLe;

    @PrePersist
    @Override
    protected void onCreate() {
        super.onCreate();
        if (typeMessage == null) {
            typeMessage = TypeContenu.TEXTE;
        }
    }

    // ── Méthodes métier ───────────────────────────────────────────────────────

    /** Retourne true si le message a été supprimé par son auteur. */
    public boolean estSupprime() {
        return supprimeLe != null;
    }

    /** Retourne true si c'est un message texte. */
    public boolean estTextuel() {
        return TypeContenu.TEXTE.equals(typeMessage);
    }

    /** Retourne true si c'est une note vocale. */
    public boolean estVocal() {
        return TypeContenu.VOCAL.equals(typeMessage);
    }

    /**
     * Supprime le message de façon douce.
     * Le contenu original est remplacé par un marqueur.
     */
    public void supprimer() {
        this.supprimeLe = LocalDateTime.now();
        this.contenu = "[Message supprimé]";
        this.urlFichier = null;
    }
}
