use crate::chat::process_message;
use chrono::{DateTime, NaiveDate, TimeZone, Utc};
use regex::Regex;
use serenity::all::{
  Color,
  CommandInteraction,
  CommandOptionType,
  Context,
  CreateCommand,
  CreateCommandOption,
  CreateEmbed,
  CreateEmbedFooter,
  EditInteractionResponse,
  Timestamp,
};
use siren_core::data::events::Event;

pub async fn run(ctx: &Context, command: &CommandInteraction) {
  // Create the initial response
  process_message(ctx, command, true).await;

  // Process the command options
  let title = command
    .data
    .options
    .first()
    .unwrap()
    .value
    .as_str()
    .unwrap();
  // let datetime_string = command.data.options.get(1).unwrap().value.as_str().unwrap();
  let description = command
    .data
    .options
    .get(2)
    .map(|option| option.value.as_str().unwrap());

  // Parse the guild ID and author ID
  let guild_id = command.guild_id.unwrap();
  let author_id = command.user.id;

  // Parse the datetime string into a DateTime object
  let date_time = Utc::now();

  // Create the event
  let event = Event {
    id: uuid::Uuid::new_v4(),
    guild_id: guild_id.get() as i64,
    author_id: author_id.get() as i64,
    title: title.to_string(),
    date_time,
    description: description.map(|s| s.to_string()),
    rsvp: vec![],
  };

  // Save the event to the database
  event.insert().await.unwrap();

  // Create the response embed
  let embed_footer = CreateEmbedFooter::new(format!("Created by {}", command.user.name));
  let embed = CreateEmbed::new()
    .title(title)
    .color(Color::TEAL)
    .timestamp(Timestamp::now())
    .description(description.unwrap_or(""))
    .field("Time", date_time.to_rfc2822(), false)
    .footer(embed_footer);
  let builder = EditInteractionResponse::new().embed(embed);
  match command.edit_response(&ctx.http, builder).await {
    Ok(_) => {}
    Err(err) => {
      log::error!("Failed to create schedule embed: {err}");
    }
  }
}

pub fn register() -> CreateCommand {
  CreateCommand::new("schedule")
    .description("Schedule a new event")
    .add_option(
      CreateCommandOption::new(CommandOptionType::String, "title", "The title of the event")
        .required(true),
    )
    .add_option(
      CreateCommandOption::new(
        CommandOptionType::String,
        "datetime",
        "The date and time of the event",
      )
      .required(true),
    )
    .add_option(CreateCommandOption::new(
      CommandOptionType::String,
      "description",
      "A description of the event",
    ))
}

// The datetime string can be formatted in the following ways:
// (in) XX <seconds, minutes, hours, days, weeks>
// (at) YYYY-MM-DD HH:MM (AM/PM)
// (at) MM DD (YYYY) HH:MM (AM/PM)
#[allow(dead_code)]
fn parse_datetime(input: &str) -> Option<DateTime<Utc>> {
  let regexes = vec![
    Regex::new(r"(?i)^\(?at\)?\s+(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2})\s*(AM|PM)?$").unwrap(),
    Regex::new(r"(?i)^\(?at\)?\s+(\d{2})\s+(\d{2})\s*(\d{4})?\s+(\d{2}):(\d{2})\s*(AM|PM)?$")
      .unwrap(),
    // ... add other regexes here
  ];

  for regex in regexes {
    if let Some(captures) = regex.captures(input) {
      if captures.len() == 7 {
        // Matches the second format
        let (year, month, day) = (
          captures.get(1).unwrap().as_str().parse().unwrap_or(1970),
          captures.get(2).unwrap().as_str().parse().unwrap_or(1),
          captures.get(3).unwrap().as_str().parse().unwrap_or(1),
        );

        let (mut hour, minute) = (
          captures.get(4).unwrap().as_str().parse().unwrap_or(0),
          captures.get(5).unwrap().as_str().parse().unwrap_or(0),
        );

        if let Some(am_pm) = captures.get(6) {
          if am_pm.as_str().eq_ignore_ascii_case("PM") && hour != 12 {
            hour += 12;
          }
          if am_pm.as_str().eq_ignore_ascii_case("AM") && hour == 12 {
            hour = 0;
          }
        }

        // Create a NaiveDate instance from year, month, day
        let naive_date =
          NaiveDate::from_ymd_opt(year, month, day).expect("Invalid date parameters");

        // Create a NaiveDateTime instance from NaiveDate and time components
        let naive_time = naive_date
          .and_hms_opt(hour, minute, 0)
          .expect("Invalid time parameters");

        // Convert the NaiveDateTime to a DateTime<Utc>
        return Some(Utc.from_utc_datetime(&naive_time));
      }
      // handle other cases
    }
  }

  None
}
