use sea_orm_migration::{prelude::*, sea_query::Expr};

#[derive(DeriveMigrationName)]
pub struct Migration;

#[derive(DeriveIden)]
enum AudioTracks {
    Table,
    AlbumId,
    Published,
    PublishedAt,
}

#[derive(DeriveIden)]
enum AudioAlbums {
    Table,
    Id,
}

#[async_trait::async_trait]
impl MigrationTrait for Migration {
    async fn up(&self, m: &SchemaManager) -> Result<(), DbErr> {
        m.drop_foreign_key(
            ForeignKey::drop()
                .name("fk-audio_tracks-album_id-to-audio_albums")
                .table(AudioTracks::Table)
                .to_owned(),
        )
        .await?;

        m.alter_table(
            Table::alter()
                .table(AudioTracks::Table)
                .modify_column(ColumnDef::new(AudioTracks::AlbumId).uuid().null())
                .add_column(
                    ColumnDef::new(AudioTracks::Published)
                        .boolean()
                        .not_null()
                        .default(false),
                )
                .add_column(
                    ColumnDef::new(AudioTracks::PublishedAt)
                        .timestamp_with_time_zone()
                        .null(),
                )
                .to_owned(),
        )
        .await?;

        m.create_foreign_key(
            ForeignKey::create()
                .name("fk-audio_tracks-album_id-to-audio_albums")
                .from(AudioTracks::Table, AudioTracks::AlbumId)
                .to(AudioAlbums::Table, AudioAlbums::Id)
                .on_delete(ForeignKeyAction::SetNull)
                .on_update(ForeignKeyAction::Cascade)
                .to_owned(),
        )
        .await?;

        m.get_connection()
            .execute_unprepared(
                r#"
                UPDATE audio_tracks t
                SET published = TRUE,
                    published_at = COALESCE(a.published_at, CURRENT_TIMESTAMP)
                FROM audio_albums a
                WHERE t.album_id = a.id
                  AND a.published = TRUE
                "#,
            )
            .await?;

        m.create_index(
            Index::create()
                .name("idx-audio_tracks-published")
                .table(AudioTracks::Table)
                .col(AudioTracks::Published)
                .to_owned(),
        )
        .await?;

        Ok(())
    }

    async fn down(&self, m: &SchemaManager) -> Result<(), DbErr> {
        m.drop_index(
            Index::drop()
                .name("idx-audio_tracks-published")
                .table(AudioTracks::Table)
                .to_owned(),
        )
        .await?;

        m.drop_foreign_key(
            ForeignKey::drop()
                .name("fk-audio_tracks-album_id-to-audio_albums")
                .table(AudioTracks::Table)
                .to_owned(),
        )
        .await?;

        m.alter_table(
            Table::alter()
                .table(AudioTracks::Table)
                .drop_column(AudioTracks::PublishedAt)
                .drop_column(AudioTracks::Published)
                .modify_column(
                    ColumnDef::new(AudioTracks::AlbumId)
                        .uuid()
                        .not_null()
                        .default(Expr::cust("'00000000-0000-0000-0000-000000000000'::uuid")),
                )
                .to_owned(),
        )
        .await?;

        m.create_foreign_key(
            ForeignKey::create()
                .name("fk-audio_tracks-album_id-to-audio_albums")
                .from(AudioTracks::Table, AudioTracks::AlbumId)
                .to(AudioAlbums::Table, AudioAlbums::Id)
                .on_delete(ForeignKeyAction::Cascade)
                .on_update(ForeignKeyAction::Cascade)
                .to_owned(),
        )
        .await?;

        Ok(())
    }
}
