use crate::handler::get_songbird;
use dashmap::DashMap;
use serde::Serialize;
use serenity::model::prelude::GuildId;
use songbird::tracks::PlayMode;
use std::{
  collections::VecDeque,
  sync::{Arc, OnceLock},
};

/// Metadata for a single track stored in our queue.
#[derive(Debug, Clone, Serialize)]
pub struct TrackInfo {
  pub title: String,
  pub url: String,
}

/// Global map of guild_id → ordered queue of TrackInfo.
/// Initialised once by the bot handler's `ready` event.
static TRACK_QUEUES: OnceLock<Arc<DashMap<u64, VecDeque<TrackInfo>>>> = OnceLock::new();

/// Call once from the `ready` event handler to initialise the store.
pub fn init_track_queues() {
  TRACK_QUEUES
    .set(Arc::new(DashMap::new()))
    .ok();
}

/// Returns a reference to the global TRACK_QUEUES map.
fn queues() -> &'static Arc<DashMap<u64, VecDeque<TrackInfo>>> {
  TRACK_QUEUES
    .get()
    .expect("TRACK_QUEUES not initialised – call init_track_queues() in the ready handler")
}

/// Append one or more tracks to the end of a guild's queue.
pub fn enqueue_tracks(guild_id: u64, tracks: Vec<TrackInfo>) {
  let mut entry = queues().entry(guild_id).or_default();
  for t in tracks {
    entry.push_back(t);
  }
}

/// Remove and return the front track (called when a track finishes).
pub fn pop_front(guild_id: u64) -> Option<TrackInfo> {
  queues()
    .get_mut(&guild_id)
    .and_then(|mut q: dashmap::mapref::one::RefMut<u64, VecDeque<TrackInfo>>| q.pop_front())
}

/// Clear the entire queue for a guild (called on stop).
pub fn clear_queue(guild_id: u64) {
  if let Some(mut q) = queues().get_mut(&guild_id) {
    let q: &mut VecDeque<TrackInfo> = q.value_mut();
    q.clear();
  }
}

/// Return a snapshot of the current queue for a guild.
/// Index 0 is the currently-playing track, index 1+ are upcoming.
pub fn get_queue(guild_id: u64) -> Vec<TrackInfo> {
  queues()
    .get(&guild_id)
    .map(|q: dashmap::mapref::one::Ref<u64, VecDeque<TrackInfo>>| {
      q.iter().cloned().collect()
    })
    .unwrap_or_default()
}

/// Returns `true` if the bot is currently paused in the given guild.
/// Encapsulates the songbird dependency so `siren-api` doesn't need it directly.
pub async fn get_is_paused(guild_id: u64) -> bool {
  let manager = get_songbird();
  let serenity_guild_id = GuildId::from(guild_id);
  if let Some(handler_lock) = manager.get(serenity_guild_id) {
    let handler = handler_lock.lock().await;
    let current = handler.queue().current();
    drop(handler);
    if let Some(track) = current {
      return track
        .get_info()
        .await
        .map(|info| info.playing == PlayMode::Pause)
        .unwrap_or(false);
    }
  }
  false
}
