use crate::{
  chat::{create_message_response, edit_response, process_message},
  handler::get_songbird,
};
use serenity::{
  all::{CommandInteraction, CommandOptionType, CreateCommand, CreateCommandOption},
  model::prelude::GuildId,
  prelude::*,
};
use siren_core::data::guilds::GuildCache;
use songbird::Songbird;
use std::sync::Arc;

pub async fn run(ctx: &Context, command: &CommandInteraction) {
  // Process the command options
  let volume = match command.data.options.first() {
    Some(o) => o.value.as_i64().unwrap() as i32,
    None => {
      log::warn!(
        "{} attempted to change the volume without a volume option",
        command.user.id.get()
      );
      create_message_response(ctx, command, "Volume option is missing".to_string(), false).await;
      return;
    }
  };

  // Create the initial response
  process_message(ctx, command, false).await;

  // Get the songbird manager
  let manager = get_songbird();

  // Extract the guild ID
  let guild_id = match &command.guild_id {
    Some(guild_id) => guild_id,
    None => {
      edit_response(
        ctx,
        command,
        "Unable to find the current server ID".to_string(),
      )
      .await;
      return;
    }
  };

  // Set the volume
  set_volume(manager, guild_id, volume).await;
  log::debug!("<{guild_id}> Setting the volume to {}", volume);
  edit_response(ctx, command, format!("Setting the volume to {}", volume)).await;
}

pub async fn set_volume(manager: &Arc<Songbird>, guild_id: &GuildId, volume: i32) {
  // Format volume to f32 bound between 0.0 and 1.0
  let bound_volume = volume.clamp(0, 100) as f32 / 100.0;

  // Update the guild cache
  let mut guild_cache = GuildCache::find_by_id(guild_id.get() as i64).await.unwrap();
  guild_cache.volume = volume;
  guild_cache.update().await.unwrap();

  // Update the volume of the songbird handler
  if let Some(handler_lock) = manager.get(guild_id.to_owned()) {
    let handler = handler_lock.lock().await;
    for track_handle in handler.queue().current_queue().iter() {
      if let Err(err) = track_handle.set_volume(bound_volume) {
        log::error!("Unable to set volume: {err}");
      }
    }
  }
}

pub fn register() -> CreateCommand {
  CreateCommand::new("volume")
    .description("Set the audio player volume")
    .add_option(
      CreateCommandOption::new(
        CommandOptionType::Integer,
        "volume",
        "Volume between 0 and 100",
      )
      .required(true),
    )
}
