process.env.FFMPEG_PATH = require('ffmpeg-static');
const { Client, GatewayIntentBits, Events, EmbedBuilder, PermissionsBitField } = require('discord.js');
const { DisTube } = require('distube');
const { SoundCloudPlugin } = require('@distube/soundcloud');
const { SpotifyPlugin } = require('@distube/spotify');
const play = require('play-dl');
const { 
    joinVoiceChannel, 
    createAudioPlayer, 
    createAudioResource, 
    AudioPlayerStatus,
    StreamType
} = require('@discordjs/voice');
const { CronJob } = require('cron');
const path = require('path');
const fs = require('fs');

// Load environment variables
require('dotenv').config({ path: path.join(__dirname, '.env') });

const client = new Client({
    intents: [
        GatewayIntentBits.Guilds,
        GatewayIntentBits.GuildVoiceStates,
        GatewayIntentBits.GuildMessages,
        GatewayIntentBits.MessageContent,
        GatewayIntentBits.GuildMembers // Added to fetch members for alarm
    ]
});

// Detect libsodium
try {
    const sodium = require('libsodium-wrappers');
    sodium.ready.then(() => {
        logToFile("Encryption library (libsodium) is ready.");
    });
} catch (e) {
    logToFile("Warning: libsodium-wrappers not found or failed to load.");
}

const distube = new DisTube(client, {
    emitNewSongOnly: true,
    plugins: [
        new SoundCloudPlugin(),
        new SpotifyPlugin(),
    ],
    emitAddSongWhenCreatingQueue: false,
});

const VC_ID = process.env.VC_ID;
const AUDIO_PATH = path.join(__dirname, 'assets', 'audio', 'sahur.mp3');
const PREFIX = '!';

function logToFile(message) {
    const logMessage = `[${new Date().toISOString()}] ${message}\n`;
    try {
        fs.appendFileSync(path.join(__dirname, 'bot.log'), logMessage);
    } catch (err) {
        console.error('Failed to write to log file:', err);
    }
    console.log(message);
}

async function playLocalIndependent(channel) {
    if (!fs.existsSync(AUDIO_PATH)) {
        logToFile(`Audio file not found: ${AUDIO_PATH}`);
        return;
    }

    try {
        // Leave DisTube first to avoid collision
        await distube.voices.leave(channel.guild.id);

        const connection = joinVoiceChannel({
            channelId: channel.id,
            guildId: channel.guild.id,
            adapterCreator: channel.guild.voiceAdapterCreator,
        });

        const player = createAudioPlayer();
        const resource = createAudioResource(AUDIO_PATH, {
            inputType: StreamType.Arbitrary
        });

        player.play(resource);
        connection.subscribe(player);

        player.on(AudioPlayerStatus.Idle, () => {
            connection.destroy();
        });

        player.on('error', error => {
            logToFile(`Audio Player Error: ${error.message}`);
            connection.destroy();
        });
    } catch (err) {
        logToFile(`Independent play error: ${err.message}`);
    }
}

client.once(Events.ClientReady, () => {
    logToFile(`Bot berhasil login!`);
    logToFile(`Ready! Logged in as ${client.user.tag}`);
    logToFile(`FFMPEG Path: ${process.env.FFMPEG_PATH}`);

    // Sahur Alarm
    const rawSahurTime = process.env.SAHUR_TIME || '03:30'; 
    let cronTime = '30 3 * * *';
    
    if (rawSahurTime.includes(':')) {
        const [hour, minute] = rawSahurTime.split(':');
        cronTime = `${parseInt(minute)} ${parseInt(hour)} * * *`;
    } else {
        cronTime = rawSahurTime;
    }

    try {
        new CronJob(cronTime, async () => {
            logToFile('Sahur alarm triggered!');
            const guild = client.guilds.cache.first();
            if (!guild) return;
            const channel = guild.channels.cache.get(VC_ID);
            if (channel && fs.existsSync(AUDIO_PATH)) {
                try {
                    await playLocalIndependent(channel);
                    logToFile('Alarm playing via independent @discordjs/voice.');
                } catch (err) {
                    logToFile(`Alarm play error: ${err.message}`);
                }
            }
        }, null, true, 'Asia/Jakarta');
        logToFile(`Alarm scheduled at ${cronTime}`);
    } catch (e) {
        logToFile(`Failed to schedule alarm: ${e.message}`);
    }
});

// Slash Command Handler
client.on(Events.InteractionCreate, async interaction => {
    if (!interaction.isChatInputCommand()) return;

    const { commandName } = interaction;
    const voiceChannel = interaction.member?.voice.channel;

    try {
        if (commandName === 'join') {
            if (!voiceChannel) return interaction.reply({ content: 'Anda harus berada di voice channel!', ephemeral: true });
            await interaction.deferReply();
            await distube.voices.join(voiceChannel, { selfDeaf: false, selfMute: false });
            await interaction.editReply('Sudah join! 🎧');
        }

        else if (commandName === 'testsahur') {
            if (!voiceChannel) return interaction.reply({ content: 'Anda harus berada di voice channel!', ephemeral: true });
            if (!fs.existsSync(AUDIO_PATH)) return interaction.reply({ content: `File audio tidak ditemukan di ${AUDIO_PATH}`, ephemeral: true });
            
            await interaction.deferReply();
            logToFile(`Playing local file independently: ${AUDIO_PATH}`);
            try {
                await playLocalIndependent(voiceChannel);
                await interaction.editReply('Memainkan suara sahur... 📢');
            } catch (e) {
                logToFile(`Error in testsahur: ${e.message}`);
                await interaction.editReply(`Gagal memutar audio: ${e.message}`);
            }
        }

        else if (commandName === 'play') {
            await interaction.deferReply();
            const query = interaction.options.getString('query');
            const voiceChannel = interaction.member?.voice.channel;
            
            if (!voiceChannel) return interaction.editReply({ content: 'Anda harus berada di voice channel!' });
            
            try {
                let url = query;
                let title = query;
                const validation = await play.validate(query);
                
                logToFile(`Validation for "${query}": ${validation}`);

                if (!validation || validation === 'search') {
                    logToFile(`Searching via play-dl for: ${query}`);
                    const searchResults = await play.search(query, { limit: 1 });
                    
                    if (!searchResults || searchResults.length === 0) {
                        return interaction.editReply('Lagu tidak ditemukan!');
                    }
                    
                    url = searchResults[0].url;
                    title = searchResults[0].title;
                } else {
                    // It's a URL, attempt to get title
                    try {
                        const info = await play.video_info(url);
                        title = info.video_details.title;
                        url = info.video_details.url;
                    } catch (err) {
                        logToFile(`Info fetch error: ${err.message}`);
                    }
                }
                
                logToFile(`Playing: ${url}`);
                await distube.play(voiceChannel, url, {
                    member: interaction.member,
                    textChannel: interaction.channel,
                    metadata: { interaction, songTitle: title }
                });
                
                await interaction.editReply(`Memainkan: **${title}**... 🎶`);
            } catch (e) {
                logToFile(`Play Error: ${e.message}`);
                if (interaction.deferred) {
                    await interaction.editReply(`Terjadi kesalahan: ${e.message}`);
                }
            }
        }

        else if (commandName === 'pause') {
            distube.pause(interaction.guildId);
            await interaction.reply('Musik dipause. ⏸️');
        }

        else if (commandName === 'resume') {
            distube.resume(interaction.guildId);
            await interaction.reply('Musik dilanjutkan. ▶️');
        }

        else if (commandName === 'skip') {
            await distube.skip(interaction.guildId);
            await interaction.reply('Lagu dilewati! ⏭️');
        }

        else if (commandName === 'stop') {
            await distube.stop(interaction.guildId);
            await interaction.reply('Musik dihentikan dan antrean dihapus. 👋');
        }
    } catch (error) {
        logToFile(`Interaction Error (${commandName}): ${error.message}`);
        if (!interaction.replied && !interaction.deferred) {
            await interaction.reply({ content: `Terjadi kesalahan: ${error.message}`, ephemeral: true });
        } else {
            await interaction.editReply({ content: `Terjadi kesalahan: ${error.message}`, ephemeral: true });
        }
    }
});

// Prefix Command Handler (Legacy/Backup)
client.on(Events.MessageCreate, async message => {
    if (message.author.bot || !message.content.startsWith(PREFIX)) return;

    const args = message.content.slice(PREFIX.length).trim().split(/ +/);
    const command = args.shift().toLowerCase();
    const voiceChannel = message.member?.voice.channel;

    try {
        if (command === 'play') {
            const query = args.join(' ');
            if (!voiceChannel) return message.reply('Anda harus berada di voice channel!');
            if (!query) return message.reply('Masukkan judul atau link lagu!');
            
            try {
                let url = query;
                let title = query;
                const validation = await play.validate(query);
                
                if (!validation || validation === 'search') {
                    const searchResults = await play.search(query, { limit: 1 });
                    if (!searchResults || searchResults.length === 0) return message.reply('Lagu tidak ditemukan!');
                    url = searchResults[0].url;
                    title = searchResults[0].title;
                } else {
                    try {
                        const info = await play.video_info(url);
                        title = info.video_details.title;
                        url = info.video_details.url;
                    } catch (err) {
                        logToFile(`Prefix info fetch error: ${err.message}`);
                    }
                }

                message.reply(`🔍 Memainkan: **${title}**...`);
                
                await distube.play(voiceChannel, url, {
                    member: message.member,
                    textChannel: message.channel,
                    message
                });
            } catch (e) {
                logToFile(`Message Play Error: ${e.message}`);
                message.reply(`❌ Error: ${e.message}`);
            }
        } else if (['skip', 'stop', 'pause', 'resume'].includes(command)) {
            if (!voiceChannel) return message.reply('Anda harus berada di voice channel!');
            const method = command === 'skip' ? 'skip' : (command === 'stop' ? 'stop' : (command === 'pause' ? 'pause' : 'resume'));
            await distube[method](message.guildId);
            message.reply(`${command} berhasil!`);
        } else if (command === 'testsahur') {
            if (!voiceChannel) return message.reply('Anda harus berada di voice channel!');
            try {
                await playLocalIndependent(voiceChannel);
                message.reply('Mengetes suara sahur... 📢');
            } catch (e) {
                message.reply(`❌ Error: ${e.message}`);
            }
        }
    } catch (error) {
        logToFile(`Message Command Error: ${error.message}`);
        message.reply(`❌ Error: ${error.message}`);
    }
});

// DisTube Events
distube
    .on('playSong', (queue, song) => {
        queue.textChannel.send(`🎵 Sekarang memutar: **${song.name}** - \`${song.formatDuration}\`\nRequested by: ${song.user}`);
    })
    .on('addSong', (queue, song) => {
        queue.textChannel.send(`✅ **${song.name}** ditambahkan ke antrean oleh ${song.user}`);
    })
    .on('error', (channel, e) => {
        logToFile(`DisTube Error: ${e.message || e}`);
        if (e.message && e.message.includes('Sign in to confirm you’re not a bot')) {
            if (channel) channel.send(`❌ YouTube memblokir akses bot. Silakan coba link dari SoundCloud atau Spotify.`);
        } else if (channel) {
            channel.send(`❌ Terjadi kesalahan: ${(e.message || e).toString().slice(0, 2000)}`);
        }
    });

// Handle uncaught errors to prevent crash
process.on('unhandledRejection', error => {
    logToFile(`Unhandled Rejection: ${error.message}`);
    console.error(error);
});

process.on('uncaughtException', error => {
    logToFile(`Uncaught Exception: ${error.message}`);
    console.error(error);
});

// Login
client.login(process.env.DISCORD_TOKEN);
