use log::warn;
use rocket::{
    delete, get,
    http::CookieJar,
    post,
    serde::json::{json, Json},
    State,
};
use serenity::client::Context;
use sqlx::{MySql, Pool};

use crate::web::{
    check_authorization,
    consts::{
        MAX_CONTENT_LENGTH, MAX_EMBED_AUTHOR_LENGTH, MAX_EMBED_DESCRIPTION_LENGTH,
        MAX_EMBED_FIELDS, MAX_EMBED_FIELD_TITLE_LENGTH, MAX_EMBED_FIELD_VALUE_LENGTH,
        MAX_EMBED_FOOTER_LENGTH, MAX_EMBED_TITLE_LENGTH, MAX_URL_LENGTH, MAX_USERNAME_LENGTH,
    },
    routes::{
        dashboard::{template_name_default, DeleteReminderTemplate, ReminderTemplate},
        JsonResult,
    },
};

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

    match sqlx::query_as_unchecked!(
        ReminderTemplate,
        "SELECT * FROM reminder_template WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?)",
        id
    )
    .fetch_all(pool.inner())
    .await
    {
        Ok(templates) => Ok(json!(templates)),
        Err(e) => {
            warn!("Could not fetch templates from {}: {:?}", id, e);

            json_err!("Could not get templates")
        }
    }
}

#[post("/api/guild/<id>/templates", data = "<reminder_template>")]
pub async fn create_reminder_template(
    id: u64,
    reminder_template: Json<ReminderTemplate>,
    cookies: &CookieJar<'_>,
    ctx: &State<Context>,
    pool: &State<Pool<MySql>>,
) -> JsonResult {
    check_authorization(cookies, ctx.inner(), id).await?;

    // validate lengths
    check_length!(MAX_CONTENT_LENGTH, reminder_template.content);
    check_length!(MAX_EMBED_DESCRIPTION_LENGTH, reminder_template.embed_description);
    check_length!(MAX_EMBED_TITLE_LENGTH, reminder_template.embed_title);
    check_length!(MAX_EMBED_AUTHOR_LENGTH, reminder_template.embed_author);
    check_length!(MAX_EMBED_FOOTER_LENGTH, reminder_template.embed_footer);
    check_length_opt!(MAX_EMBED_FIELDS, reminder_template.embed_fields);
    if let Some(fields) = &reminder_template.embed_fields {
        for field in &fields.0 {
            check_length!(MAX_EMBED_FIELD_VALUE_LENGTH, field.value);
            check_length!(MAX_EMBED_FIELD_TITLE_LENGTH, field.title);
        }
    }
    check_length_opt!(MAX_USERNAME_LENGTH, reminder_template.username);
    check_length_opt!(
        MAX_URL_LENGTH,
        reminder_template.embed_footer_url,
        reminder_template.embed_thumbnail_url,
        reminder_template.embed_author_url,
        reminder_template.embed_image_url,
        reminder_template.avatar
    );

    // validate urls
    check_url_opt!(
        reminder_template.embed_footer_url,
        reminder_template.embed_thumbnail_url,
        reminder_template.embed_author_url,
        reminder_template.embed_image_url,
        reminder_template.avatar
    );

    let name = if reminder_template.name.is_empty() {
        template_name_default()
    } else {
        reminder_template.name.clone()
    };

    match sqlx::query!(
        "INSERT INTO reminder_template
        (guild_id,
         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
        ) VALUES ((SELECT id FROM guilds WHERE guild = ?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
         ?, ?, ?, ?, ?, ?, ?)",
        id,
        name,
        reminder_template.attachment,
        reminder_template.attachment_name,
        reminder_template.avatar,
        reminder_template.content,
        reminder_template.embed_author,
        reminder_template.embed_author_url,
        reminder_template.embed_color,
        reminder_template.embed_description,
        reminder_template.embed_footer,
        reminder_template.embed_footer_url,
        reminder_template.embed_image_url,
        reminder_template.embed_thumbnail_url,
        reminder_template.embed_title,
        reminder_template.embed_fields,
        reminder_template.interval_seconds,
        reminder_template.interval_days,
        reminder_template.interval_months,
        reminder_template.tts,
        reminder_template.username,
    )
    .fetch_all(pool.inner())
    .await
    {
        Ok(_) => Ok(json!({})),
        Err(e) => {
            warn!("Could not create template for {}: {:?}", id, e);

            json_err!("Could not create template")
        }
    }
}

#[delete("/api/guild/<id>/templates", data = "<delete_reminder_template>")]
pub async fn delete_reminder_template(
    id: u64,
    delete_reminder_template: Json<DeleteReminderTemplate>,
    cookies: &CookieJar<'_>,
    ctx: &State<Context>,
    pool: &State<Pool<MySql>>,
) -> JsonResult {
    check_authorization(cookies, ctx.inner(), id).await?;

    match sqlx::query!(
        "DELETE FROM reminder_template WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?) AND id = ?",
        id, delete_reminder_template.id
    )
    .fetch_all(pool.inner())
    .await
    {
        Ok(_) => {
            Ok(json!({}))
        }
        Err(e) => {
            warn!("Could not delete template from {}: {:?}", id, e);

            json_err!("Could not delete template")
        }
    }
}
