/**
 * Baileys WhatsApp API Server
 * Deploy di cPanel Node.js App
 * 
 * Author: RT/RW Net System
 */

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

const app = express();
app.use(express.json({ limit: '10mb' }));

// cPanel akan assign port otomatis via environment variable
const PORT = process.env.PORT || 3000;
const AUTH_DIR = path.join(__dirname, 'auth_info');
const LOG_FILE = path.join(__dirname, 'baileys.log');

// Optional API Key untuk security
const API_KEY = process.env.API_KEY || '';

// Ensure auth directory exists
if (!fs.existsSync(AUTH_DIR)) {
    fs.mkdirSync(AUTH_DIR, { recursive: true });
}

// Simple logging function
function log(message) {
    const timestamp = new Date().toISOString();
    const logMessage = `[${timestamp}] ${message}\n`;
    console.log(logMessage.trim());
    try {
        fs.appendFileSync(LOG_FILE, logMessage);
    } catch (e) {
        // Ignore log write errors
    }
}

// API Key middleware (optional)
if (API_KEY) {
    app.use((req, res, next) => {
        // Skip auth untuk health check
        if (req.path === '/' || req.path === '/status') {
            return next();
        }
        
        const apiKey = req.headers['x-api-key'] || req.query.api_key;
        if (apiKey !== API_KEY) {
            return res.status(401).json({ 
                success: false, 
                error: 'Unauthorized - Invalid API Key' 
            });
        }
        next();
    });
}

let sock = null;
let qrCode = null;
let connectionState = 'disconnected';
let phoneNumber = null;
let reconnectAttempts = 0;
const MAX_RECONNECT = 5;
let startTime = Date.now();

async function startSock() {
    try {
        log('Starting WhatsApp socket...');
        
        const { state, saveCreds } = await useMultiFileAuthState(AUTH_DIR);
        const { version } = await fetchLatestBaileysVersion();
        
        sock = makeWASocket({
            version,
            auth: state,
            printQRInTerminal: false,
            logger: pino({ level: 'silent' }),
            generateHighQualityLinkPreview: false,
            syncFullHistory: false,
            markOnlineOnConnect: true,
            browser: ['Ubuntu', 'Chrome', '120.0.0.0'],
            keepAliveIntervalMs: 30000,
        });
        
        // Handle QR code
        sock.ev.on('qr', async (qr) => {
            log('QR Code received');
            try {
                qrCode = await toDataURL(qr);
                connectionState = 'waiting_for_scan';
                reconnectAttempts = 0;
            } catch (e) {
                log('Error generating QR: ' + e.message);
            }
        });
        
        // Handle connection updates
        sock.ev.on('connection.update', async (update) => {
            const { connection, lastDisconnect } = update;
            log(`Connection update: ${connection}`);
            
            if (connection === 'close') {
                const statusCode = lastDisconnect?.error?.output?.statusCode;
                const reason = DisconnectReason[statusCode] || 'unknown';
                log(`Connection closed. Reason: ${reason} (${statusCode})`);
                
                connectionState = 'disconnected';
                qrCode = null;
                phoneNumber = null;
                
                // Auto-reconnect kecuali logged out
                if (statusCode !== DisconnectReason.loggedOut) {
                    if (reconnectAttempts < MAX_RECONNECT) {
                        reconnectAttempts++;
                        log(`Reconnecting... Attempt ${reconnectAttempts}/${MAX_RECONNECT}`);
                        setTimeout(() => startSock(), 3000);
                    } else {
                        log('Max reconnect attempts reached. Please restart app.');
                    }
                } else {
                    log('Logged out from WhatsApp. Deleting session...');
                    try {
                        fs.rmSync(AUTH_DIR, { recursive: true, force: true });
                        fs.mkdirSync(AUTH_DIR, { recursive: true });
                    } catch (e) {
                        log('Error deleting auth: ' + e.message);
                    }
                    setTimeout(() => startSock(), 2000);
                }
            } else if (connection === 'open') {
                connectionState = 'connected';
                qrCode = null;
                reconnectAttempts = 0;
                phoneNumber = sock.user?.id?.split(':')[0] || null;
                log(`✅ Connected! Phone: +${phoneNumber}`);
            }
        });
        
        // Save credentials
        sock.ev.on('creds.update', saveCreds);
        
    } catch (error) {
        log(`❌ Error starting socket: ${error.message}`);
        if (reconnectAttempts < MAX_RECONNECT) {
            reconnectAttempts++;
            setTimeout(() => startSock(), 5000);
        }
    }
}

// Start socket
startSock();

// ============ API ENDPOINTS ============

// Health check
app.get('/', (req, res) => {
    res.json({
        service: 'Baileys WhatsApp API',
        status: 'running',
        connected: connectionState === 'connected',
        uptime: Math.floor((Date.now() - startTime) / 1000),
        version: '1.0.0'
    });
});

// Status endpoint
app.get('/status', (req, res) => {
    res.json({
        success: true,
        connected: connectionState === 'connected',
        state: connectionState,
        phone: phoneNumber ? `+${phoneNumber}` : null,
        reconnectAttempts,
        uptime: Math.floor((Date.now() - startTime) / 1000)
    });
});

// Get QR code
app.get('/qr', (req, res) => {
    if (connectionState === 'connected') {
        return res.json({ 
            success: false, 
            error: 'Already connected',
            phone: phoneNumber ? `+${phoneNumber}` : null
        });
    }
    
    if (connectionState === 'waiting_for_scan' && qrCode) {
        const base64Data = qrCode.split(',')[1];
        return res.json({ 
            success: true, 
            qr: base64Data,
            state: connectionState
        });
    }
    
    res.json({ 
        success: false, 
        error: 'QR not ready. State: ' + connectionState,
        hint: 'Try again in 2-3 seconds'
    });
});

// Logout / Reset session
app.post('/logout', (req, res) => {
    try {
        if (sock) {
            sock.logout();
        }
        fs.rmSync(AUTH_DIR, { recursive: true, force: true });
        fs.mkdirSync(AUTH_DIR, { recursive: true });
        connectionState = 'disconnected';
        phoneNumber = null;
        qrCode = null;
        
        setTimeout(() => startSock(), 1000);
        
        res.json({ success: true, message: 'Logged out. Restarting...' });
    } catch (error) {
        res.status(500).json({ success: false, error: error.message });
    }
});

// Send text message
app.post('/send/text', async (req, res) => {
    if (connectionState !== 'connected') {
        return res.status(400).json({ 
            success: false, 
            error: 'Not connected. Current state: ' + connectionState 
        });
    }
    
    try {
        const { phone, message } = req.body;
        
        if (!phone || !message) {
            return res.status(400).json({ 
                success: false, 
                error: 'Phone and message are required' 
            });
        }
        
        const jid = phone.includes('@s.whatsapp.net') ? phone : `${phone}@s.whatsapp.net`;
        
        const result = await sock.sendMessage(jid, { text: message });
        log(`✅ Message sent to ${phone}`);
        
        res.json({ 
            success: true, 
            message: 'Message sent',
            messageId: result.key?.id
        });
    } catch (error) {
        log(`❌ Error sending message: ${error.message}`);
        res.status(500).json({ success: false, error: error.message });
    }
});

// Send image
app.post('/send/image', async (req, res) => {
    if (connectionState !== 'connected') {
        return res.status(400).json({ 
            success: false, 
            error: 'Not connected' 
        });
    }
    
    try {
        const { phone, image, caption } = req.body;
        const jid = phone.includes('@s.whatsapp.net') ? phone : `${phone}@s.whatsapp.net`;
        
        await sock.sendMessage(jid, { 
            image: { url: image },
            caption: caption || ''
        });
        log(`✅ Image sent to ${phone}`);
        
        res.json({ success: true, message: 'Image sent' });
    } catch (error) {
        res.status(500).json({ success: false, error: error.message });
    }
});

// Send document
app.post('/send/document', async (req, res) => {
    if (connectionState !== 'connected') {
        return res.status(400).json({ 
            success: false, 
            error: 'Not connected' 
        });
    }
    
    try {
        const { phone, document: docUrl, filename } = req.body;
        const jid = phone.includes('@s.whatsapp.net') ? phone : `${phone}@s.whatsapp.net`;
        
        await sock.sendMessage(jid, {
            document: { url: docUrl },
            fileName: filename || 'document.pdf',
            mimetype: 'application/pdf'
        });
        log(`✅ Document sent to ${phone}`);
        
        res.json({ success: true, message: 'Document sent' });
    } catch (error) {
        res.status(500).json({ success: false, error: error.message });
    }
});

// Send media (generic)
app.post('/send/media', async (req, res) => {
    if (connectionState !== 'connected') {
        return res.status(400).json({ success: false, error: 'Not connected' });
    }
    
    try {
        const { phone, type, url, caption, filename } = req.body;
        const jid = phone.includes('@s.whatsapp.net') ? phone : `${phone}@s.whatsapp.net`;
        
        let message;
        switch (type) {
            case 'image':
                message = { image: { url }, caption: caption || '' };
                break;
            case 'video':
                message = { video: { url }, caption: caption || '' };
                break;
            case 'audio':
                message = { audio: { url }, mimetype: 'audio/mpeg' };
                break;
            case 'document':
                message = { 
                    document: { url }, 
                    fileName: filename || 'document',
                    mimetype: 'application/octet-stream'
                };
                break;
            default:
                return res.status(400).json({ success: false, error: 'Invalid type' });
        }
        
        await sock.sendMessage(jid, message);
        res.json({ success: true, message: `${type} sent` });
    } catch (error) {
        res.status(500).json({ success: false, error: error.message });
    }
});

// Error handling
app.use((err, req, res, next) => {
    log(`Server error: ${err.message}`);
    res.status(500).json({ success: false, error: 'Internal server error' });
});

// Start server
app.listen(PORT, () => {
    log(`🚀 Baileys server running on port ${PORT}`);
    log(`📁 Auth directory: ${AUTH_DIR}`);
});

// Graceful shutdown
process.on('SIGTERM', () => {
    log('SIGTERM received. Shutting down gracefully...');
    if (sock) {
        sock.ws.close();
    }
    process.exit(0);
});

process.on('SIGINT', () => {
    log('SIGINT received. Shutting down...');
    if (sock) {
        sock.ws.close();
    }
    process.exit(0);
});