use crate::web::routes::dashboard::{create_reminder_template, ReminderTemplate};
use crate::web::{
    check_authorization,
    guards::transaction::Transaction,
    routes::{
        dashboard::{ImportBody, ReminderTemplateCsv},
        JsonResult,
    },
};
use base64::{prelude::BASE64_STANDARD, Engine};
use csv::{QuoteStyle, WriterBuilder};
use log::warn;
use rocket::{
    get,
    http::CookieJar,
    put,
    serde::json::{json, Json},
    State,
};
use serenity::{client::Context, model::id::GuildId};
use sqlx::{MySql, Pool};

#[get("/api/guild/<id>/export/reminder_templates")]
pub async fn export(
    id: u64,
    cookies: &CookieJar<'_>,
    ctx: &State<Context>,
    pool: &State<Pool<MySql>>,
) -> JsonResult {
    check_authorization(cookies, ctx.inner(), id).await?;

    let mut csv_writer = WriterBuilder::new().quote_style(QuoteStyle::Always).from_writer(vec![]);

    match sqlx::query_as_unchecked!(
        ReminderTemplateCsv,
        "SELECT
         name,
         attachment,
         attachment_name,
         avatar,
         content,
         embed_author,
         embed_author_url,
         embed_color,
         embed_description,
         embed_footer,
         embed_footer_url,
         embed_image_url,
         embed_thumbnail_url,
         embed_title,
         embed_fields,
         interval_seconds,
         interval_days,
         interval_months,
         tts,
         username
        FROM reminder_template WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?)",
        id
    )
    .fetch_all(pool.inner())
    .await
    {
        Ok(templates) => {
            templates.iter().for_each(|template| {
                csv_writer.serialize(template).unwrap();
            });

            match csv_writer.into_inner() {
                Ok(inner) => match String::from_utf8(inner) {
                    Ok(encoded) => Ok(json!({ "body": encoded })),

                    Err(e) => {
                        warn!("Failed to write UTF-8: {:?}", e);

                        json_err!("Failed to write UTF-8")
                    }
                },

                Err(e) => {
                    warn!("Failed to extract CSV: {:?}", e);

                    json_err!("Failed to extract CSV")
                }
            }
        }
        Err(e) => {
            warn!("Could not fetch templates from {}: {:?}", id, e);

            json_err!("Failed to query templates")
        }
    }
}

#[put("/api/guild/<id>/export/reminder_templates", data = "<body>")]
pub async fn import(
    id: u64,
    cookies: &CookieJar<'_>,
    body: Json<ImportBody>,
    ctx: &State<Context>,
    mut transaction: Transaction<'_>,
) -> JsonResult {
    check_authorization(cookies, ctx.inner(), id).await?;

    match BASE64_STANDARD.decode(&body.body) {
        Ok(body) => {
            let mut reader = csv::Reader::from_reader(body.as_slice());
            let mut count = 0;

            for result in reader.deserialize::<ReminderTemplateCsv>() {
                match result {
                    Ok(record) => {
                        let reminder_template = ReminderTemplate {
                            id: 0,
                            guild_id: 0,
                            name: record.name,
                            attachment: record.attachment,
                            attachment_name: record.attachment_name,
                            avatar: record.avatar,
                            content: record.content,
                            embed_author: record.embed_author,
                            embed_author_url: record.embed_author_url,
                            embed_color: record.embed_color,
                            embed_description: record.embed_description,
                            embed_footer: record.embed_footer,
                            embed_footer_url: record.embed_footer_url,
                            embed_image_url: record.embed_image_url,
                            embed_thumbnail_url: record.embed_thumbnail_url,
                            embed_title: record.embed_title,
                            embed_fields: record
                                .embed_fields
                                .map(|s| serde_json::from_str(&s).ok())
                                .flatten(),
                            interval_seconds: record.interval_seconds,
                            interval_days: record.interval_days,
                            interval_months: record.interval_months,
                            tts: record.tts,
                            username: record.username,
                        };

                        create_reminder_template(
                            ctx.inner(),
                            &mut transaction,
                            GuildId::new(id),
                            reminder_template,
                        )
                        .await?;

                        count += 1;
                    }

                    Err(e) => {
                        warn!("Couldn't deserialize CSV row: {:?}", e);

                        return json_err!(format!("Deserialize error: {:?}", e));
                    }
                }
            }

            match transaction.commit().await {
                Ok(_) => Ok(json!({
                    "message": format!("Imported {} reminder templates", count)
                })),

                Err(e) => {
                    warn!("Failed to commit transaction: {:?}", e);
                    json_err!("Couldn't commit transaction")
                }
            }
        }

        Err(_) => {
            json_err!("Malformed base64")
        }
    }
}
