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

// Row shape for `event`: every field is populated by sqlx from `SELECT *` / `RETURNING *`. Several
// (`slug`, `cover_image_path`, `export_epoch`, `created_at`) are not read through this struct today
// — callers that need them query the column directly — but they are part of the row and stay here so
// the struct keeps mirroring the table.
#[allow(dead_code)]
#[derive(Debug, sqlx::FromRow)]
pub struct Event {
    pub id: Uuid,
    pub slug: String,
    pub name: String,
    pub cover_image_path: Option<String>,
    pub is_active: bool,
    pub uploads_locked_at: Option<DateTime<Utc>>,
    pub export_released_at: Option<DateTime<Utc>>,
    /// Monotonic generation counter for the keepsake. Bumped in the SAME UPDATE as any change to
    /// `export_released_at` (release and reopen are its only writers). An export is downloadable
    /// iff a `done` `export_job` row carries this exact epoch — readiness is derived from that,
    /// never stored, so it cannot drift and no worker can resurrect it. See migration 014.
    pub export_epoch: i64,
    pub created_at: DateTime<Utc>,
}

impl Event {
    pub async fn find_by_slug(pool: &PgPool, slug: &str) -> Result<Option<Self>, sqlx::Error> {
        sqlx::query_as::<_, Self>("SELECT * FROM event WHERE slug = $1")
            .bind(slug)
            .fetch_optional(pool)
            .await
    }

    pub async fn create(pool: &PgPool, slug: &str, name: &str) -> Result<Self, sqlx::Error> {
        sqlx::query_as::<_, Self>("INSERT INTO event (slug, name) VALUES ($1, $2) RETURNING *")
            .bind(slug)
            .bind(name)
            .fetch_one(pool)
            .await
    }

    pub async fn find_or_create(
        pool: &PgPool,
        slug: &str,
        name: &str,
    ) -> Result<Self, sqlx::Error> {
        if let Some(event) = Self::find_by_slug(pool, slug).await? {
            return Ok(event);
        }
        Self::create(pool, slug, name).await
    }
}
