//! Repository trait and commit bundles produced by transactional chat writes.

use async_trait::async_trait;
use chrono::{DateTime, Utc};
use serde_json::Value;
use sqlx::PgPool;
use uuid::Uuid;

use crate::domain::member::RoomMember;
use crate::dto::commands::{
    AddMembers, AttachmentInput, CreateRoom, EditMessage, ListMessages, ListRooms, SearchMessages,
    SendMessage, UpdateRoom,
};
use crate::dto::results::{
    MemberView, MessagePage, MessageView, ReactionSummary, RoomPage, RoomView, SearchPage,
};
use crate::error::ChatResult;
use crate::events::ChatEventEnvelope;
use crate::ids::{MessageId, RoomId, UserId};

/// Result of inserting a message plus its outbox event.
#[derive(Debug, Clone)]
pub struct SendMessageCommit {
    pub message: MessageView,
    pub event: ChatEventEnvelope,
    pub outbox_id: Option<Uuid>,
}

/// Result of editing a message plus its outbox event.
#[derive(Debug, Clone)]
pub struct MessageMutationCommit {
    pub message: MessageView,
    pub event: ChatEventEnvelope,
    pub outbox_id: Option<Uuid>,
}

/// Result of soft-deleting a message plus its outbox event.
#[derive(Debug, Clone)]
pub struct DeleteMessageCommit {
    pub room_id: RoomId,
    pub room_seq: i64,
    pub message_id: MessageId,
    pub event: ChatEventEnvelope,
    pub outbox_id: Option<Uuid>,
}

/// Result of advancing a read cursor plus its outbox event.
#[derive(Debug, Clone)]
pub struct ReadCursorCommit {
    pub room_id: RoomId,
    pub user_id: UserId,
    pub last_read_seq: i64,
    pub last_read_message_id: Option<MessageId>,
    pub event: ChatEventEnvelope,
    pub outbox_id: Option<Uuid>,
}

/// Result of toggling a reaction plus its outbox event.
#[derive(Debug, Clone)]
pub struct ReactionCommit {
    pub room_id: RoomId,
    pub summary: ReactionSummary,
    pub event: ChatEventEnvelope,
    pub outbox_id: Option<Uuid>,
}

/// Result of a membership mutation plus its outbox event.
#[derive(Debug, Clone)]
pub struct MembersCommit {
    pub members: Vec<MemberView>,
    pub event: ChatEventEnvelope,
    pub outbox_id: Option<Uuid>,
}

/// Result of a room lifecycle mutation plus its outbox event.
#[derive(Debug, Clone)]
pub struct RoomCommit {
    pub room: RoomView,
    pub event: ChatEventEnvelope,
    pub outbox_id: Option<Uuid>,
}

/// Low-level chat persistence used by service layers; returns commit bundles with outbox ids.
#[async_trait]
pub trait ChatRepository: Send + Sync {
    async fn create_room(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        input: CreateRoom,
    ) -> ChatResult<RoomCommit>;
    async fn update_room(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        input: UpdateRoom,
    ) -> ChatResult<RoomCommit>;
    async fn archive_room(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        room_id: RoomId,
    ) -> ChatResult<RoomCommit>;
    async fn list_rooms(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        input: ListRooms,
    ) -> ChatResult<RoomPage>;
    async fn get_room(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        room_id: RoomId,
    ) -> ChatResult<RoomView>;
    async fn list_members(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        room_id: RoomId,
    ) -> ChatResult<Vec<MemberView>>;
    async fn add_members(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        input: AddMembers,
    ) -> ChatResult<MembersCommit>;
    async fn remove_member(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        room_id: RoomId,
        user_id: &str,
    ) -> ChatResult<MembersCommit>;
    async fn list_messages(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        input: ListMessages,
    ) -> ChatResult<MessagePage>;
    async fn send_message(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        input: SendMessage,
    ) -> ChatResult<SendMessageCommit>;
    async fn edit_message(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        input: EditMessage,
    ) -> ChatResult<MessageMutationCommit>;
    async fn delete_message(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        room_id: RoomId,
        message_id: MessageId,
    ) -> ChatResult<DeleteMessageCommit>;
    async fn mark_read_up_to(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        room_id: RoomId,
        seq: i64,
        message_id: Option<MessageId>,
    ) -> ChatResult<ReadCursorCommit>;
    async fn add_reaction(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        message_id: MessageId,
        emoji: &str,
    ) -> ChatResult<ReactionCommit>;
    async fn remove_reaction(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        message_id: MessageId,
        emoji: &str,
    ) -> ChatResult<ReactionCommit>;
    async fn search_messages(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        input: SearchMessages,
    ) -> ChatResult<SearchPage>;
    async fn lease_pending_outbox(
        &self,
        pool: &PgPool,
        limit: i64,
    ) -> ChatResult<Vec<(Uuid, RoomId, ChatEventEnvelope)>>;
    async fn mark_outbox_published(&self, pool: &PgPool, id: Uuid) -> ChatResult<()>;
    async fn mark_outbox_failed(&self, pool: &PgPool, id: Uuid) -> ChatResult<()>;
}
