package dev.lions.unionflow.server.entity;

import dev.lions.unionflow.server.api.enums.messagerie.StatutConversation;
import dev.lions.unionflow.server.api.enums.messagerie.TypeConversation;
import jakarta.persistence.CascadeType;
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.OneToMany;
import jakarta.persistence.PrePersist;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

/**
 * Fil de discussion entre membres d'une organisation.
 *
 * <p>Deux types sont supportés en V1 :
 * <ul>
 *   <li>{@link TypeConversation#DIRECTE} — 1-1 entre deux membres</li>
 *   <li>{@link TypeConversation#ROLE_CANAL} — membre vers un rôle officiel
 *       (PRESIDENT, TRESORIER, SECRETAIRE…). Tous les porteurs du rôle répondent.</li>
 * </ul>
 *
 * <p>Table : {@code conversations}
 *
 * @author UnionFlow Team
 * @version 4.0
 * @since 2026-04-13
 */
@Entity
@Table(
    name = "conversations",
    indexes = {
        @Index(name = "idx_conversations_organisation", columnList = "organisation_id"),
        @Index(name = "idx_conversations_statut",       columnList = "statut"),
        @Index(name = "idx_conversations_dernier_msg",  columnList = "dernier_message_at")
    }
)
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@EqualsAndHashCode(callSuper = true)
public class Conversation extends BaseEntity {

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "organisation_id", nullable = false)
    private Organisation organisation;

    @NotNull
    @Enumerated(EnumType.STRING)
    @Column(name = "type_conversation", nullable = false, length = 30)
    private TypeConversation typeConversation;

    /**
     * Rôle cible pour les ROLE_CANAL (ex : "TRESORIER", "PRESIDENT").
     * Null pour les conversations DIRECTE.
     */
    @Column(name = "role_cible", length = 50)
    private String roleCible;

    /** Titre affiché (nom du rôle ou du groupe, null pour DIRECTE). */
    @Column(name = "titre", length = 200)
    private String titre;

    @Enumerated(EnumType.STRING)
    @Builder.Default
    @Column(name = "statut", nullable = false, length = 20)
    private StatutConversation statut = StatutConversation.ACTIVE;

    @Column(name = "dernier_message_at")
    private LocalDateTime dernierMessageAt;

    @Builder.Default
    @Column(name = "nombre_messages", nullable = false)
    private Integer nombreMessages = 0;

    @Builder.Default
    @OneToMany(mappedBy = "conversation", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<ConversationParticipant> participants = new ArrayList<>();

    @Builder.Default
    @OneToMany(mappedBy = "conversation", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<Message> messages = new ArrayList<>();

    @PrePersist
    @Override
    protected void onCreate() {
        super.onCreate();
        if (statut == null) {
            statut = StatutConversation.ACTIVE;
        }
        if (nombreMessages == null) {
            nombreMessages = 0;
        }
    }

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

    /** Retourne true si la conversation accepte encore de nouveaux messages. */
    public boolean estActive() {
        return StatutConversation.ACTIVE.equals(statut);
    }

    /** Archive la conversation — plus aucun message n'est accepté. */
    public void archiver() {
        this.statut = StatutConversation.ARCHIVEE;
    }

    /** Incrémente le compteur et met à jour l'horodatage du dernier message. */
    public void enregistrerNouveauMessage() {
        this.nombreMessages = (this.nombreMessages == null ? 0 : this.nombreMessages) + 1;
        this.dernierMessageAt = LocalDateTime.now();
    }
}
