use std::time::{SystemTime, UNIX_EPOCH};

use chrono_tz::TZ_VARIANTS;
use poise::serenity_prelude::AutocompleteChoice;

use crate::time_parser::cron_next_timestamp;
use crate::{models::CtxData, time_parser::natural_parser, Context};

pub async fn timezone_autocomplete(ctx: Context<'_>, partial: &str) -> Vec<String> {
    if partial.is_empty() {
        ctx.data().popular_timezones.iter().map(|t| t.to_string()).collect::<Vec<String>>()
    } else {
        TZ_VARIANTS
            .iter()
            .filter(|tz| tz.to_string().contains(&partial))
            .take(25)
            .map(|t| t.to_string())
            .collect::<Vec<String>>()
    }
}

pub async fn macro_name_autocomplete(ctx: Context<'_>, partial: &str) -> Vec<String> {
    sqlx::query!(
        "
        SELECT name
        FROM command_macro
        WHERE
            guild_id = (SELECT id FROM guilds WHERE guild = ?)
            AND name LIKE CONCAT(?, '%')
        ",
        ctx.guild_id().unwrap().get(),
        partial,
    )
    .fetch_all(&ctx.data().database)
    .await
    .unwrap_or_default()
    .iter()
    .map(|s| s.name.clone())
    .collect()
}

pub async fn time_hint_autocomplete(ctx: Context<'_>, partial: &str) -> Vec<AutocompleteChoice> {
    if partial.is_empty() {
        vec![AutocompleteChoice::new("Start typing a time...".to_string(), "now".to_string())]
    } else {
        let timezone = ctx.timezone().await;
        let timestamp = match cron_next_timestamp(partial, timezone) {
            Some(ts) => Some(ts),
            None => natural_parser(partial, &timezone.to_string()).await,
        };

        match timestamp {
            Some(timestamp) => match SystemTime::now().duration_since(UNIX_EPOCH) {
                Ok(now) => {
                    let diff = timestamp - now.as_secs() as i64;

                    if diff < 0 {
                        vec![AutocompleteChoice::new(
                            "Time is in the past".to_string(),
                            "1 year ago".to_string(),
                        )]
                    } else {
                        if diff > 86400 {
                            vec![
                                AutocompleteChoice::new(partial.to_string(), partial.to_string()),
                                AutocompleteChoice::new(
                                    format!(
                                        "In approximately {} days, {} hours",
                                        diff / 86400,
                                        (diff % 86400) / 3600
                                    ),
                                    partial.to_string(),
                                ),
                            ]
                        } else if diff > 3600 {
                            vec![
                                AutocompleteChoice::new(partial.to_string(), partial.to_string()),
                                AutocompleteChoice::new(
                                    format!("In approximately {} hours", diff / 3600),
                                    partial.to_string(),
                                ),
                            ]
                        } else {
                            vec![
                                AutocompleteChoice::new(partial.to_string(), partial.to_string()),
                                AutocompleteChoice::new(
                                    format!("In approximately {} minutes", diff / 60),
                                    partial.to_string(),
                                ),
                            ]
                        }
                    }
                }
                Err(_) => {
                    vec![AutocompleteChoice::new(partial.to_string(), partial.to_string())]
                }
            },

            None => {
                vec![AutocompleteChoice::new("Time not recognised".to_string(), "now".to_string())]
            }
        }
    }
}
