const { default: makeWASocket, useMultiFileAuthState, DisconnectReason, fetchLatestBaileysVersion } = require('@whiskeysockets/baileys');
const { Boom } = require('@hapi/boom');
const express = require('express');
const qrcode = require('qrcode');
const path = require('path');
const fs = require('fs');
const crypto = require('crypto');
const pino = require('pino');

const logDir = path.join(__dirname, '..', 'logs');
if (!fs.existsSync(logDir)) {
    fs.mkdirSync(logDir);
}

const logFile = path.join(logDir, 'app.log');
const logStream = fs.createWriteStream(logFile, { flags: 'a' });

const originalConsoleLog = console.log;
const originalConsoleError = console.error;

console.log = (...args) => {
    const message = args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : arg).join(' ');
    logStream.write(message + '\n');
    originalConsoleLog.apply(console, args);
};

console.error = (...args) => {
    const message = args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : arg).join(' ');
    logStream.write('[ERROR] ' + message + '\n');
    originalConsoleError.apply(console, args);
};

const app = express();
const port = process.env.PORT || 3000;

const TOKEN_FILE = path.join(__dirname, '..', 'api-token.json');
let apiToken;

const loadToken = () => {
    if (fs.existsSync(TOKEN_FILE)) {
        const tokenData = fs.readFileSync(TOKEN_FILE, 'utf8');
        apiToken = JSON.parse(tokenData).token;
    } else {
        generateAndSaveToken();
    }
};

const generateAndSaveToken = () => {
    apiToken = crypto.randomBytes(32).toString('hex');
    try {
        fs.writeFileSync(TOKEN_FILE, JSON.stringify({ token: apiToken }));
        console.log('API token generated and saved.');
    } catch (error) {
        console.error('Error saving API token:', error);
    }
};

loadToken();

let sock;
let sessionActive = false;
let loggedInNumber = '';
let qrCodeData = '';
let isConnecting = false;

app.use(express.json());
app.use(express.static(path.join(__dirname, '..', 'public'), { index: false }));

app.get('/health', (req, res) => {
    res.send('OK');
});

app.get('/', (req, res) => {
    const indexPath = path.join(__dirname, '..', 'public', 'index.html');
    fs.readFile(indexPath, 'utf8', (err, data) => {
        if (err) {
            console.error('Error reading index.html:', err);
            return res.status(500).send('Error loading page');
        }
        const modifiedHtml = data.replace('<!-- API_TOKEN_PLACEHOLDER -->', apiToken);
        res.send(modifiedHtml);
    });
});

const apiAuth = (req, res, next) => {
    const token = req.headers['x-api-token'];
    if (token !== apiToken) {
        return res.status(401).json({ error: 'Unauthorized' });
    }
    next();
};

async function connectToWhatsApp() {
    console.log('Connecting to WhatsApp...');
    if (isConnecting) {
        console.log('Already connecting, returning.');
        return;
    }
    isConnecting = true;

    try {
        const authDir = path.join(__dirname, '..', 'auth');
        const { state, saveCreds } = await useMultiFileAuthState(authDir);
        
        // Fetch latest version
        const { version } = await fetchLatestBaileysVersion();
        
        sock = makeWASocket({
            version,
            auth: state,
            printQRInTerminal: true,
            logger: pino({ level: 'silent' }),
            browser: ['WhatsApp Bot', 'Chrome', '1.0.0'],
            syncFullHistory: false,
            markOnlineOnConnect: false,
            generateHighQualityLinkPreview: false
        });

        sock.ev.on('connection.update', async (update) => {
            console.log('Connection update:', JSON.stringify(update));
            const { connection, lastDisconnect, qr } = update;
            
            if (qr) {
                console.log('QR Code received, generating data URL...');
                try {
                    qrCodeData = await qrcode.toDataURL(qr);
                    console.log('QR Code generated successfully');
                } catch (error) {
                    console.error('Error generating QR code:', error);
                }
            }
            
            if (connection === 'close') {
                isConnecting = false;
                sessionActive = false;
                loggedInNumber = '';
                qrCodeData = '';
                
                const shouldReconnect = (lastDisconnect?.error instanceof Boom) 
                    ? lastDisconnect.error.output.statusCode !== DisconnectReason.loggedOut
                    : true;

                console.log('Connection closed. Should reconnect:', shouldReconnect);
                
                if (shouldReconnect) {
                    setTimeout(() => connectToWhatsApp(), 3000);
                } else {
                    console.log('Logged out, deleting session...');
                    if (fs.existsSync(authDir)) {
                        fs.rmSync(authDir, { recursive: true, force: true });
                    }
                    setTimeout(() => connectToWhatsApp(), 3000);
                }
            } else if (connection === 'open') {
                isConnecting = false;
                sessionActive = true;
                loggedInNumber = sock.user.id.split(':')[0];
                qrCodeData = '';
                console.log('WhatsApp connection opened successfully!');
                console.log('Logged in as:', loggedInNumber);
            }
        });

        sock.ev.on('creds.update', saveCreds);
        
    } catch (error) {
        console.error('Error in connectToWhatsApp:', error);
        isConnecting = false;
        setTimeout(() => connectToWhatsApp(), 5000);
    }
}

// Web interface endpoints
app.get('/status', (req, res) => {
    res.json({
        sessionActive,
        loggedInNumber,
        isConnecting
    });
});

app.get('/qr', (req, res) => {
    if (sessionActive) {
        return res.status(400).json({ error: 'Session is already active' });
    }
    if (!qrCodeData && !isConnecting) {
        connectToWhatsApp();
    }
    res.json({ qr: qrCodeData, isConnecting });
});

app.post('/logout', async (req, res) => {
    try {
        if (sock) {
            await sock.logout();
            sessionActive = false;
            loggedInNumber = '';
            qrCodeData = '';
            res.json({ success: true, message: 'Logged out successfully' });
        } else {
            res.status(400).json({ error: 'Client not initialized' });
        }
    } catch (error) {
        console.error('Logout error:', error);
        res.status(500).json({ error: 'Failed to logout' });
    }
});

app.get('/logs', (req, res) => {
    fs.readFile(logFile, 'utf8', (err, data) => {
        if (err) {
            console.error(err);
            return res.status(500).json({ error: 'Failed to read log file' });
        }
        res.header('Content-Type', 'text/plain');
        res.send(data);
    });
});

// API endpoints with auth
app.post('/api/send-message', apiAuth, async (req, res) => {
    if (!sessionActive) {
        return res.status(400).json({ error: 'Session not active' });
    }
    const { number, message } = req.body;
    if (!number || !message) {
        return res.status(400).json({ error: 'Number and message are required' });
    }

    try {
        const jid = `${number}@s.whatsapp.net`;
        await sock.sendMessage(jid, { text: message });
        res.json({ success: true, message: 'Message sent successfully' });
    } catch (error) {
        console.error('Send message error:', error);
        res.status(500).json({ error: 'Failed to send message' });
    }
});

app.post('/api/send-bulk', apiAuth, async (req, res) => {
    if (!sessionActive) {
        return res.status(400).json({ error: 'Session not active' });
    }
    const { numbers, message, delay } = req.body;
    if (!numbers || !Array.isArray(numbers) || !message) {
        return res.status(400).json({ error: 'Numbers (array) and message are required' });
    }

    const parsedDelay = parseInt(delay, 10);
    const delayInMs = (isNaN(parsedDelay) ? 2 : parsedDelay) * 1000;

    console.log(`Starting bulk message sending with a delay of ${delayInMs}ms between messages.`);

    for (let i = 0; i < numbers.length; i++) {
        try {
            const number = numbers[i];
            const jid = `${number}@s.whatsapp.net`;
            console.log(`Sending message to ${number}...`);
            await sock.sendMessage(jid, { text: message });
            console.log(`Message sent to ${number}. Waiting for ${delayInMs}ms...`);
            await new Promise(resolve => setTimeout(resolve, delayInMs));
        } catch (error) {
            console.error(`Failed to send message to ${numbers[i]}`, error);
        }
    }

    console.log('Bulk message sending complete.');
    res.json({ success: true, message: 'Bulk messaging complete.' });
});

app.get('/api/status', apiAuth, (req, res) => {
    res.json({
        sessionActive,
        loggedInNumber
    });
});

app.get('/api/api-token', apiAuth, (req, res) => {
    res.json({ token: apiToken });
});

app.post('/api/regenerate-token', apiAuth, (req, res) => {
    generateAndSaveToken();
    res.json({ token: apiToken });
});

app.listen(port, () => {
    console.log(`Server is running on port ${port}`);
    connectToWhatsApp();
});

process.on('unhandledRejection', (err) => {
    console.error('Unhandled Rejection:', err);
});