const makeWASocket = require('@whiskeysockets/baileys').default;
const { 
    useMultiFileAuthState, 
    DisconnectReason,
    fetchLatestBaileysVersion
} = require('@whiskeysockets/baileys');
const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const QRCode = require('qrcode');
const pino = require('pino');
const axios = require('axios');
const path = require('path');
const fs = require('fs');

const app = express();
const server = http.createServer(app);
const io = new Server(server, {
    cors: { origin: "*" }
});

app.use(express.json());

const sessions = new Map();
// const store = makeInMemoryStore({ logger: pino({ level: 'silent' }) });

async function createSession(instanceId, userId) {
    const sessionDir = path.join(__dirname, 'sessions', instanceId);
    if (!fs.existsSync(sessionDir)) {
        fs.mkdirSync(sessionDir, { recursive: true });
    }

    const { state, saveCreds } = await useMultiFileAuthState(sessionDir);
    const { version } = await fetchLatestBaileysVersion();

    const sock = makeWASocket({
        version,
        printQRInTerminal: true,
        auth: state,
        logger: pino({ level: 'silent' }),
    });

    // store.bind(sock.ev);

    sessions.set(instanceId, { sock, qr: null, status: 'disconnected' });

    sock.ev.on('connection.update', async (update) => {
        const { connection, lastDisconnect, qr } = update;
        const apiUrl = process.env.WHBELL_API_URL || 'http://localhost/api';
        
        if (qr) {
            const qrDataURL = await QRCode.toDataURL(qr);
            sessions.get(instanceId).qr = qrDataURL;
            io.emit(`qr-${instanceId}`, qrDataURL);
            
            // Notify Laravel
            try {
                console.log(`Syncing QR to Laravel for ${instanceId}...`);
                await axios.post(`${apiUrl}/internal/instances/update`, {
                    instance_id: instanceId,
                    qr_code: qrDataURL,
                    status: 'disconnected'
                });
            } catch (e) {
                console.error(`Sync Error (QR): ${e.message}`);
            }
        }

        if (connection === 'close') {
            const statusCode = lastDisconnect.error?.output?.statusCode;
            const shouldReconnect = statusCode !== DisconnectReason.loggedOut;
            
            console.log(`Connection closed for ${instanceId}. Reason: ${shouldReconnect ? 'Reconnectable' : 'Logged Out'} (Code: ${statusCode})`);

            // Notify Laravel about disconnection
            try {
                console.log(`Syncing disconnection to Laravel for ${instanceId}...`);
                await axios.post(`${apiUrl}/internal/instances/update`, {
                    instance_id: instanceId,
                    status: 'disconnected'
                });
            } catch (e) {
                console.error(`Sync Error (Disconnect): ${e.message}`);
            }

            if (shouldReconnect) {
                console.log(`Attempting to reconnect ${instanceId}...`);
                createSession(instanceId, userId);
            } else {
                console.log(`Permanently disconnected ${instanceId}. Cleaning up session files.`);
                sessions.delete(instanceId);
                if (fs.existsSync(sessionDir)) {
                    fs.rmSync(sessionDir, { recursive: true, force: true });
                }
                io.emit(`status-${instanceId}`, 'disconnected');
            }
        } else if (connection === 'open') {
            const user = sock.user.id.split(':')[0];
            sessions.get(instanceId).status = 'connected';
            sessions.get(instanceId).qr = null;
            io.emit(`status-${instanceId}`, 'connected');

            // Notify Laravel
            try {
                console.log(`Syncing connection to Laravel for ${instanceId}...`);
                await axios.post(`${apiUrl}/internal/instances/update`, {
                    instance_id: instanceId,
                    status: 'connected',
                    number: user
                });
            } catch (e) {
                console.error(`Sync Error (Connect): ${e.message}`);
            }
        }
    });

    sock.ev.on('creds.update', saveCreds);
    
    return sock;
}

// API Routes
app.post('/sessions/create', async (req, res) => {
    const { instance_id, user_id } = req.body;
    if (sessions.has(instance_id)) {
        return res.json({ status: 'exists', session: sessions.get(instance_id).status });
    }
    createSession(instance_id, user_id);
    res.json({ status: 'initializing' });
});

app.get('/qr/:instance_id', (req, res) => {
    const { instance_id } = req.params;
    const session = sessions.get(instance_id);
    
    if (!session) {
        // Automatically try to create session if it doesn't exist
        createSession(instance_id, 'SYSTEM');
        return res.json({ qr: null, status: 'initializing' });
    }
    
    res.json({
        qr: session.qr,
        status: session.status
    });
});

app.post('/numbers/check', async (req, res) => {
    const { instance_id, number } = req.body;
    console.log(`Checking number ${number} via instance ${instance_id}`);
    
    const session = sessions.get(instance_id);
    
    if (!session || session.status !== 'connected') {
        console.log('Session not connected for check');
        return res.status(400).json({ error: 'Instance not connected' });
    }
    
    try {
        // Sanitize number: remove spaces, +, -, etc.
        const cleanNumber = number.replace(/\D/g, '');
        const jid = `${cleanNumber}@s.whatsapp.net`;
        
        console.log(`Querying WhatsApp for JID: ${jid}`);
        const results = await session.sock.onWhatsApp(jid);
        
        if (results && results.length > 0) {
            const result = results[0];
            res.json({ exists: result.exists, jid: result.jid });
        } else {
            res.json({ exists: false });
        }
    } catch (e) {
        console.error('Error in onWhatsApp check:', e);
        res.status(500).json({ error: e.message });
    }
});

app.post('/messages/send', async (req, res) => {
    console.log('Received message request:', req.body);
    const { instance_id, to, body } = req.body;
    const session = sessions.get(instance_id);
    
    if (!session) {
        console.log('Session not found for instance:', instance_id);
        return res.status(400).json({ error: 'Instance not connected' });
    }
    
    if (session.status !== 'connected') {
        console.log('Session is not connected:', session.status);
        return res.status(400).json({ error: 'Instance not connected' });
    }
    
    try {
        console.log(`Sending message to ${to}`);
        const jid = to.includes('@s.whatsapp.net') ? to : `${to}@s.whatsapp.net`;
        await session.sock.sendMessage(jid, { text: body });
        console.log('Message sent successfully!');
        res.json({ status: 'sent' });
    } catch (e) {
        console.error('Error sending message:', e);
        res.status(500).json({ error: e.message });
    }
});

const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
    console.log(`WhatsApp Engine running on port ${PORT}`);
    
    // Load existing sessions
    const sessionsDir = path.join(__dirname, 'sessions');
    if (fs.existsSync(sessionsDir)) {
        const files = fs.readdirSync(sessionsDir);
        for (const file of files) {
            const stat = fs.statSync(path.join(sessionsDir, file));
            if (stat.isDirectory()) {
                console.log(`Loading session: ${file}`);
                createSession(file, 'SYSTEM');
            }
        }
    }
});
