use clap::Parser;
use dialtone_axum::media::{
    media_dir_exists, media_type_from_file_name, owned_media_url, visit_media_dir, MediaError,
};
use dialtone_common::{
    ap::{ap_object::ApObjectType, create_actor_id},
    media::{SYSTEM_BANNERS_PUN, SYSTEM_ICONS_PUN},
    rest::ap_objects::ap_object_model::CreateOwnedApObject,
    utils::version::DT_VERSION,
};
use dialtone_sqlx::{
    control::ap_object::create::create_ap_object,
    db::{ap_object::fetch::fetch_ap_object, get_pooled_connection},
    logic::ap_object::new::new_media_ap_object,
};
use sqlx::{Pool, Postgres};

/// Process site owned media.
#[derive(Parser, Debug)]
#[clap(name = "process_media", version = DT_VERSION)]
struct Opts {
    /// DNS host names (e.g. thefoo.example)
    #[clap(value_parser, short, long)]
    host_name: String,
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    dotenv::dotenv().ok();
    let opts: Opts = Opts::parse();
    let pg_pool = get_pooled_connection().await?;
    println!("Processing media for {}", opts.host_name);

    process_actor_media(&opts.host_name, *SYSTEM_BANNERS_PUN, &pg_pool).await?;
    process_actor_media(&opts.host_name, *SYSTEM_ICONS_PUN, &pg_pool).await?;
    Ok(())
}

async fn process_actor_media(
    host_name: &str,
    pun: &str,
    pg_pool: &Pool<Postgres>,
) -> anyhow::Result<()> {
    if media_dir_exists(host_name, pun).await? {
        println!("Examining media for {pun}@{host_name}");
        visit_media_dir(host_name, pun, |entry| async move {
            let file_name = entry.file_name().to_string_lossy().to_string();
            let new_ap_object = CreateOwnedApObject {
                name: None,
                media_type: media_type_from_file_name(&file_name),
                ap_type: ApObjectType::Image,
                content: None,
                summary: None,
                owner_data: None,
                to: None,
                cc: None,
                bto: None,
                bcc: None,
            };
            let url = owned_media_url(host_name, pun, &file_name)?;
            let actor_id = create_actor_id(host_name, pun);
            let ap_object =
                new_media_ap_object(host_name, &actor_id, &url, &file_name, pun, &new_ap_object);
            let ap_object_id = ap_object
                .id
                .as_ref()
                .ok_or(MediaError::ErrorWhileVisiting)?;
            println!("Processing {file_name} for {ap_object_id}");
            let fetch_result = fetch_ap_object(pg_pool, &ap_object_id).await?;
            if fetch_result.is_some() {
                println!("{ap_object_id} already exists.");
            } else {
                let create_result = create_ap_object(pg_pool, &ap_object, host_name).await?;
                println!("Created AP image {create_result}");
            }
            Ok(())
        })
        .await?;
    }
    Ok(())
}
