use chrono::Utc;
use chrono_tz::{Tz, TZ_VARIANTS};
use levenshtein::levenshtein;
use poise::{
    serenity_prelude::{CreateEmbed, CreateEmbedFooter},
    CreateReply,
};
use serde::{Deserialize, Serialize};

use crate::{
    commands::autocomplete::timezone_autocomplete,
    consts::THEME_COLOR,
    models::CtxData,
    utils::{Extract, Recordable},
    Context, Error,
};

#[derive(Serialize, Deserialize, Extract)]
pub struct Options {
    pub timezone: Option<String>,
}

impl Recordable for Options {
    async fn run(self, ctx: Context<'_>) -> Result<(), Error> {
        let mut user_data = ctx.author_data().await.unwrap();

        let footer_text = format!("Current timezone: {}", user_data.timezone);

        if let Some(timezone) = self.timezone {
            match timezone.parse::<Tz>() {
                Ok(tz) => {
                    user_data.timezone = timezone.clone();
                    user_data.commit_changes(&ctx.data().database).await;

                    let now = Utc::now().with_timezone(&tz);

                    ctx.send(
                        CreateReply::default().embed(
                            CreateEmbed::new()
                                .title("Timezone Set")
                                .description(format!(
                                "Timezone has been set to **{}**. Your current time should be `{}`",
                                timezone,
                                now.format("%H:%M")
                            ))
                                .color(*THEME_COLOR),
                        ),
                    )
                    .await?;
                }

                Err(_) => {
                    let filtered_tz = TZ_VARIANTS
                        .iter()
                        .filter(|tz| {
                            timezone.contains(&tz.to_string())
                                || tz.to_string().contains(&timezone)
                                || levenshtein(&tz.to_string(), &timezone) < 4
                        })
                        .take(25)
                        .map(|t| t.to_owned())
                        .collect::<Vec<Tz>>();

                    let fields = filtered_tz.iter().map(|tz| {
                        (
                            tz.to_string(),
                            format!("🕗 `{}`", Utc::now().with_timezone(tz).format("%H:%M")),
                            true,
                        )
                    });

                    ctx.send(
                    CreateReply::default().embed(
                        CreateEmbed::new()
                            .title("Timezone Not Recognized")
                            .description(concat!(
                                "Possibly you meant one of the following timezones,",
                                " otherwise click [here](https://gist.github.com/JellyWX/",
                                "913dfc8b63d45192ad6cb54c829324ee):"
                            ))
                            .color(*THEME_COLOR)
                            .fields(fields)
                            .footer(CreateEmbedFooter::new(footer_text))
                            .url(
                                "https://gist.github.com/JellyWX/913dfc8b63d45192ad6cb54c829324ee",
                            ),
                    ),
                )
                .await?;
                }
            }
        } else {
            let popular_timezones_iter = ctx.data().popular_timezones.iter().map(|t| {
                (
                    t.to_string(),
                    format!("🕗 `{}`", Utc::now().with_timezone(t).format("%H:%M")),
                    true,
                )
            });

            ctx.send(
            CreateReply::default().embed(
                CreateEmbed::new()
                    .title("Timezone Usage")
                    .description(
                        "**Usage:**
`/timezone Name`

**Example:**
`/timezone Europe/London`

You may want to use one of the popular timezones below, otherwise click [here](https://gist.github.com/JellyWX/913dfc8b63d45192ad6cb54c829324ee):",
                    )
                    .color(*THEME_COLOR)
                    .fields(popular_timezones_iter)
                    .footer(CreateEmbedFooter::new(footer_text))
                    .url("https://gist.github.com/JellyWX/913dfc8b63d45192ad6cb54c829324ee"),
            ),
        )
        .await?;
        }

        Ok(())
    }
}

/// Select your timezone
#[poise::command(slash_command, rename = "timezone", identifying_name = "timezone")]
pub async fn command(
    ctx: Context<'_>,
    #[description = "Timezone to use from this list: https://gist.github.com/JellyWX/913dfc8b63d45192ad6cb54c829324ee"]
    #[autocomplete = "timezone_autocomplete"]
    timezone: Option<String>,
) -> Result<(), Error> {
    (Options { timezone }).run(ctx).await
}
