use std::sync::Arc;

use log::{error, warn};

use serenity::{prelude::*, model::prelude::GuildId};
use serenity::builder::CreateApplicationCommand;
use serenity::model::application::interaction::application_command::ApplicationCommandInteraction;
use songbird::Songbird;

use crate::storage::guilds::InsertGuild;

use super::{get_songbird, create_response, edit_response};

pub async fn run(ctx: &Context, command: &ApplicationCommandInteraction) {
  // Get the volume
  let volume = match command.data.options.get(0) {
    Some(t) => match &t.value {
      Some(v) => match v.as_i64() {
        Some(p) => p as i32,
        None => {
          warn!("Unable to get volume option as a string");
          if let Err(why) = create_response(&ctx, &command, format!("Volume option is missing")).await {
            error!("Failed to create response message: {}", why);
          }
          return;
        }
      }
      None => {
        warn!("Missing volume option value");
        if let Err(why) = create_response(&ctx, &command, format!("Volume option is missing")).await {
          error!("Failed to create response message: {}", why);
        }
        return;
      }
    }
    None => {
      warn!("Missing volume option");
      if let Err(why) = create_response(&ctx, &command, format!("Volume option is missing")).await {
        error!("Failed to create response message: {}", why);
      }
      return;
    }
  };

  // Create the initial response
  if let Err(why) = create_response(&ctx, &command, "Processing command...".to_string()).await {
    error!("Failed to create response message: {}", why);
    return;
  }

  let guild_id = match command.guild_id {
    Some(g) => g,
    None => {
      if let Err(why) = edit_response(&ctx, &command, "Unable to join voice channel".to_string()).await {
        error!("Failed to edit response message: {}", why);
      }
      return;
    }
  };
  let manager = get_songbird(ctx).await;
  set_volume(manager, guild_id, volume).await;
  if let Err(why) = edit_response(&ctx, &command, format!("Setting the volume to {}", volume)).await {
    error!("Failed to set the volume: {}", why);
  }
}

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 volume = std::cmp::min(100, std::cmp::max(0, volume));
  let bound_volume = volume as f32 / 100.0;
  let _ = InsertGuild::update_audio(guild_id.0 as i64, volume);

  if let Some(handler_lock) = manager.get(guild_id) {
    let handler = handler_lock.lock().await;
    for (_, track_handle) in handler.queue().current_queue().iter().enumerate() {
      let _ = track_handle.set_volume(bound_volume);
    }
  }
}

pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand {
  command.name("volume").description("Set the audio player volume").create_option(|option| { option
    .name("volume")
    .description("Volume between 0 and 100")
    .kind(serenity::model::prelude::command::CommandOptionType::Integer)
    .required(true)
  })
}