use crate::model::event::ChatMsg;
use crate::repo::Repo;
use chrono::{DateTime, Utc};
use sqlx::PgPool;
use uuid::Uuid;

#[derive(Clone)]
pub struct MessageRepository {
	pool: PgPool
}

impl MessageRepository {
	pub(crate) fn new(pool: PgPool) -> Self {
		Self { pool }
	}

	// TODO: caching with redis
	async fn get_by_id(&self, id: Uuid) -> Option<ChatMsg> {
		sqlx::query!(
			"SELECT m.id, u.username, u.nickname, u.id as user_id, m.content, m.created_at
            FROM messages m
            JOIN users u ON m.user_id = u.id
            WHERE m.id = $1",
		   	id
		).fetch_optional(&self.pool).await.ok().flatten().map(|row| ChatMsg {
			id: row.id,
			display_name: Some(row.nickname.unwrap_or(row.username)),
			user_id: row.user_id,
			text: row.content,
			timestamp: row.created_at,
		})
	}


	// TODO! caching with redis
	pub async fn create_new(
		&self, msg: ChatMsg, channel_id: i64
	) -> Result<(), sqlx::Error> {
		sqlx::query!(
			"INSERT INTO messages (id, channel_id, user_id, content, created_at)
			VALUES ($1, $2, $3, $4, $5)",
			msg.id,
			channel_id,
			msg.user_id,
			msg.text,
			msg.timestamp
		).execute(&self.pool).await.map_err(|_| sqlx::Error::RowNotFound)?;
		Ok(())
	}

	pub async fn update_text(&self, id: Uuid, text: &str) -> Result<(), sqlx::Error> {
		sqlx::query!(
			"UPDATE messages SET content = $1 WHERE id = $2",
			text,
			id
		).execute(&self.pool).await?;
		Ok(())
	}

	/// TODO: caching with redis
	pub async fn get_latest_by_channel_desc(
		&self, channel_id: i64, limit: usize, page: usize
	) -> Result<Vec<ChatMsg>, sqlx::Error> {
		sqlx::query!(
			"SELECT m.id, u.username, u.nickname, u.id as user_id, m.content, m.created_at
            FROM messages m
            JOIN users u ON m.user_id = u.id
            WHERE m.channel_id = $1
            ORDER BY m.created_at DESC
            LIMIT $2 OFFSET $3",
			channel_id,
			limit as i64,
			page as i64
		).fetch_all(&self.pool).await.map(|messages| {
			messages.into_iter().map(|msg| {
				ChatMsg {
					id: msg.id,
					display_name: Some(msg.nickname.unwrap_or(msg.username)),
					user_id: msg.user_id,
					text: msg.content,
					timestamp: msg.created_at,
				}
			}).collect::<Vec<_>>()
		})
	}
}





















