use modules::*;
use serenity::all::ChannelId;
use serenity::async_trait;
use serenity::model::channel::Message;
use serenity::model::gateway::Ready;
use serenity::prelude::*;
use songbird::SerenityInit;
use songbird::get;
use songbird::input::HlsRequest;
use songbird::input::Input;
use songbird::tracks::TrackHandle;
use std::collections::HashMap;
use std::io;
use std::process::Command;
use std::process::Stdio;
use std::sync::Arc;
pub mod modules;

type TrackMap = Arc<Mutex<HashMap<u64, TrackHandle>>>;
struct Handler {
    track_map: TrackMap,
}
fn get_user_voice_channel(ctx: &Context, msg: &Message) -> Option<ChannelId> {
    let guild_id = msg.guild_id?;
    let guild = ctx.cache.guild(guild_id)?;
    guild
        .voice_states
        .get(&msg.author.id)
        .and_then(|vs| vs.channel_id)
}

#[async_trait]
impl EventHandler for Handler {
    async fn message(&self, ctx: Context, msg: Message) {
        if msg.content == "!ping"
            && let Err(why) = msg.channel_id.say(&ctx.http, "Pong!").await
        {
            println!("Error sending message: {why:?}");
        }
        if msg.content == "!join" {
            let guild_id = match msg.guild_id {
                Some(g) => g,
                None => return,
            };
            let channel_id = match get_user_voice_channel(&ctx, &msg) {
                Some(c) => c,
                None => {
                    let _ = msg
                        .channel_id
                        .say(&ctx.http, "You must be in a voice channel")
                        .await;
                    return;
                }
            };

            let manager = get(&ctx).await.expect("Songbird not initialized").clone();

            let _ = manager.join(guild_id, channel_id).await;

            let _ = msg
                .channel_id
                .say(&ctx.http, "Joined your voice channel!")
                .await;
        }
        if msg.content == "!leave" {
            let guild_id = match msg.guild_id {
                Some(g) => g,
                None => return,
            };
            let manager = songbird::get(&ctx).await.unwrap();
            if manager.get(guild_id).is_some() {
                let _ = manager.remove(guild_id).await;
                let _ = msg
                    .channel_id
                    .say(&ctx.http, "Left the voice channel")
                    .await;
            }
        }
        if msg.content.starts_with("!play") {
            let url = msg
                .content
                .strip_prefix("!play ")
                .unwrap_or("")
                .trim()
                .to_string();

            if url.is_empty() {
                let _ = msg.reply(&ctx, "Please provide a YouTube URL.").await;
                return;
            }
            let guild_id = msg.guild_id.unwrap();
            let manager = songbird::get(&ctx)
                .await
                .expect("Songbird Voice client placed in at initialisation.")
                .clone();
            let handler_lock = if let Some(handler) = manager.get(guild_id) {
                handler
            } else {
                let channel_id = get_user_voice_channel(&ctx, &msg);
                match channel_id {
                    Some(c) => manager.join(guild_id, c).await.unwrap(),
                    None => {
                        let _ = msg.reply(&ctx, "Join a voice channel first!").await;
                        return;
                    }
                }
            };
            let output = Command::new("./yt-dlp")
                .args(["-f", "bestaudio", "-g", &url])
                .stdout(Stdio::piped())
                .output()
                .expect("Failed");
            let url_bytes = output.stdout;
            let url = String::from_utf8(url_bytes).expect("Failed");
            let mut handler = handler_lock.lock().await;
            let input = Input::from(HlsRequest::new(reqwest::Client::new(), url.to_string()));
            let track_handle = handler.play_input(input);
            let _ = track_handle.play();
            self.track_map
                .lock()
                .await
                .insert(guild_id.into(), track_handle);
            let _ = msg.channel_id.say(&ctx.http, "🎶 Playing...").await;
        }
        if msg.content == "!pause" {
            let guild_id = match msg.guild_id {
                Some(g) => g,
                None => return,
            };
            if let Some(handle) = self.track_map.lock().await.get(&guild_id.into()) {
                let _ = handle.pause();
            }
        }
        if msg.content == "!resume" {
            let guild_id = match msg.guild_id {
                Some(g) => g,
                None => return,
            };
            if let Some(handle) = self.track_map.lock().await.get(&guild_id.into()) {
                let _ = handle.play();
            }
        }
        if msg.content == "!stop" {
            let guild_id = match msg.guild_id {
                Some(g) => g,
                None => return,
            };
            if let Some(handle) = self.track_map.lock().await.get(&guild_id.into()) {
                let _ = handle.stop();
            }
        }
    }
    async fn ready(&self, _: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
    }
}
#[tokio::main]
async fn main() {
    println!("RhythmWorks  Copyright (C) 2025  James Brotosky\n
This program comes with ABSOLUTELY NO WARRANTY\n
This is free software, and you are welcome to redistribute it under certain conditions.");
    updator::update().await;
    println!("Please paste in your bot token");
    let mut input = String::new();
    io::stdin().read_line(&mut input).expect("Failed to read line");
    let token = input.trim();
    let intents = GatewayIntents::GUILD_MESSAGES
        | GatewayIntents::GUILDS
        | GatewayIntents::DIRECT_MESSAGES
        | GatewayIntents::MESSAGE_CONTENT
        | GatewayIntents::GUILD_VOICE_STATES;
    let track_map: TrackMap = Arc::new(Mutex::new(HashMap::new()));
    let mut client = Client::builder(&token, intents)
        .event_handler(Handler { track_map })
        .register_songbird()
        .await
        .expect("Err creating client");
    if let Err(why) = client.start().await {
        println!("Client error: {why:?}");
    }
}
