const express = require('express');
const path = require('path');
const fs = require('fs');
const { spawn } = require('child_process');
const axios = require('axios');

const app = express();
const PORT = 1346;

let scrapingSessions = {};

app.use(express.json());
app.use(express.static(path.join(__dirname)));

// Serve main dashboard
app.get('/', (req, res) => {
    res.sendFile(path.join(__dirname, 'index.html'));
});

// Get all configurations
app.get('/api/configs', (req, res) => {
    try {
        const configs = JSON.parse(fs.readFileSync('configs.json', 'utf8'));
        res.json(configs);
    } catch (error) {
        console.error('Error reading configs:', error);
        res.status(500).json({ error: 'Failed to read configurations' });
    }
});

// Start scraping with selected config
app.post('/api/start-scraping', (req, res) => {
    const { configId } = req.body;
    
    if (!configId) {
        return res.status(400).json({ success: false, message: 'Config ID required' });
    }
    
    const configs = JSON.parse(fs.readFileSync('configs.json', 'utf8'));
    const config = configs.find(c => c.id === configId);
    
    if (!config) {
        return res.status(404).json({ success: false, message: 'Configuration not found' });
    }
    
    if (scrapingSessions[configId]?.isRunning) {
        return res.status(400).json({ success: false, message: `Scraping already running for ${config.stateName}` });
    }
    
    // Initialize session
    scrapingSessions[configId] = {
        isRunning: true,
        needsCaptcha: false,
        processedTenders: 0,
        currentPage: 1,
        processedSerials: [],
        logs: [`Starting scraper for ${config.stateName}...`],
        sessionId: generateSessionId(),
        startTime: Date.now(),
        process: null,
        captchaError: null,
        folderName: null,
        config: config
    };

    try {
        const scraperProcess = spawn('node', ['n7.js', JSON.stringify(config)], {
            stdio: ['pipe', 'pipe', 'pipe']
        });

        scrapingSessions[configId].process = scraperProcess;

        scraperProcess.stdout.on('data', (data) => {
            parseScraperOutput(data.toString(), configId);
        });

        scraperProcess.stderr.on('data', (data) => {
            console.error(`Scraper error [${configId}]:`, data.toString());
            if (scrapingSessions[configId]) {
                scrapingSessions[configId].logs.push(`Error: ${data.toString()}`);
            }
        });

        scraperProcess.on('close', (code) => {
            console.log(`Scraper [${configId}] ended with code ${code}`);
            setTimeout(() => {
                cleanupSession(configId);
            }, 3000);
        });

        scraperProcess.on('error', (error) => {
            console.error(`Scraper process error [${configId}]:`, error);
            if (scrapingSessions[configId]) {
                scrapingSessions[configId].logs.push(`Process error: ${error.message}`);
            }
            cleanupSession(configId);
        });

        res.json({ success: true, sessionId: scrapingSessions[configId].sessionId, configId });

    } catch (error) {
        scrapingSessions[configId].isRunning = false;
        scrapingSessions[configId].logs.push(`Error starting scraper: ${error.message}`);
        res.status(500).json({ success: false, message: error.message });
    }
});

// Get status for specific config
app.get('/api/status/:configId', (req, res) => {
    const { configId } = req.params;
    const session = scrapingSessions[configId];
    
    if (!session) {
        return res.json({ 
            isRunning: false,
            processedTenders: 0,
            currentPage: 0,
            progress: 0,
            uptime: '0s'
        });
    }
    
    const progress = session.processedTenders > 0 ? 
        Math.min((session.processedTenders / 400) * 100, 100) : 0;
    
    res.json({
        ...session,
        progress,
        uptime: session.startTime ? getUptime(session.startTime) : '0s',
        isCompleted: !session.isRunning && session.processedTenders > 0
    });
});

// Get all active sessions
app.get('/api/all-sessions', (req, res) => {
    const sessions = Object.keys(scrapingSessions).map(configId => {
        const session = scrapingSessions[configId];
        return {
            configId,
            stateName: session.config?.stateName || 'Unknown',
            sourceCode: session.config?.sourceCode || '',
            isRunning: session.isRunning,
            processedTenders: session.processedTenders,
            currentPage: session.currentPage,
            uptime: getUptime(session.startTime),
            startTime: session.startTime,
            progress: session.processedTenders > 0 ? 
                Math.min((session.processedTenders / 400) * 100, 100) : 0
        };
    });
    
    res.json(sessions);
});

// Stop scraping for specific config
app.post('/api/stop-scraping/:configId', (req, res) => {
    const { configId } = req.params;
    const session = scrapingSessions[configId];
    
    if (!session || !session.isRunning || !session.process) {
        return res.status(400).json({ success: false, message: 'No active scraping process' });
    }

    try {
        session.process.kill('SIGTERM');
        setTimeout(() => {
            if (session.process) {
                session.process.kill('SIGKILL');
            }
        }, 5000);
        
        cleanupSession(configId);
        res.json({ success: true, message: 'Scraping stopped successfully' });
    } catch (error) {
        cleanupSession(configId);
        res.json({ success: true, message: 'Process terminated' });
    }
});

// Submit captcha for specific config
app.post('/api/submit-captcha/:configId', (req, res) => {
    const { configId } = req.params;
    const { captcha } = req.body;
    const session = scrapingSessions[configId];
    
    if (!captcha || !session || !session.needsCaptcha) {
        return res.status(400).json({ success: false, message: 'Invalid captcha submission' });
    }

    if (session.process && session.process.stdin && session.process.stdin.writable) {
        try {
            session.process.stdin.write(captcha + '\n');
            session.needsCaptcha = false;
            session.captchaError = null;
            session.logs.push(`Captcha submitted: ${captcha}`);
            res.json({ success: true });
        } catch (error) {
            res.status(500).json({ success: false, message: 'Failed to submit captcha' });
        }
    } else {
        res.status(500).json({ success: false, message: 'Process not available for input' });
    }
});

// Serve captcha image for specific config
app.get('/captcha-image/:configId', (req, res) => {
    const captchaImagesDir = path.join(__dirname, 'captcha_images');
    
    if (!fs.existsSync(captchaImagesDir)) {
        return res.status(404).json({ error: 'Captcha images directory not found' });
    }
    
    try {
        const files = fs.readdirSync(captchaImagesDir);
        const captchaFiles = files.filter(file => 
            (file.startsWith('captcha_search_') || file.startsWith('captcha_tender_documents_')) && 
            file.endsWith('.png')
        );
        
        if (captchaFiles.length > 0) {
            captchaFiles.sort((a, b) => {
                const timeA = parseInt(a.match(/\d+/)?.[0] || '0');
                const timeB = parseInt(b.match(/\d+/)?.[0] || '0');
                return timeB - timeA;
            });
            
            const imagePath = path.join(captchaImagesDir, captchaFiles[0]);
            
            res.setHeader('Content-Type', 'image/png');
            res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
            res.setHeader('Pragma', 'no-cache');
            res.setHeader('Expires', '0');
            res.sendFile(path.resolve(imagePath));
        } else {
            res.status(404).json({ error: 'No captcha images found' });
        }
    } catch (error) {
        res.status(404).json({ error: 'Captcha image not found' });
    }
});

// Reset all systems
app.post('/api/reset', (req, res) => {
    try {
        Object.keys(scrapingSessions).forEach(configId => {
            if (scrapingSessions[configId].process) {
                scrapingSessions[configId].process.kill('SIGKILL');
            }
        });
        scrapingSessions = {};
        res.json({ success: true, message: 'All sessions reset successfully' });
    } catch (error) {
        scrapingSessions = {};
        res.json({ success: true, message: 'System reset with errors' });
    }
});

// Parse scraper output for specific config
function parseScraperOutput(output, configId) {
    const session = scrapingSessions[configId];
    if (!session) return;
    
    const lines = output.split('\n').filter(line => line.trim());
    
    lines.forEach(line => {
        session.logs.push(line);
        
        // Extract folder name
        if (line.includes('Created download folder:')) {
            const folderMatch = line.match(/Created download folder:\s*(.+)/);
            if (folderMatch) {
                session.folderName = folderMatch[1].trim();
                console.log(`[${configId}] Captured folder name: ${session.folderName}`);
            }
        }
        
        // Track tender processing
        const tenderMatch = line.match(/Processing tender (\d+):/);
        if (tenderMatch) {
            session.processedTenders = parseInt(tenderMatch[1]);
        }
        
        // Track serial numbers
        const serialMatch = line.match(/S\.No\s*(\d+)/);
        if (serialMatch) {
            const serial = serialMatch[1];
            if (!session.processedSerials.includes(serial)) {
                session.processedSerials.push(serial);
            }
        }
        
        // Track page number
        const pageMatch = line.match(/Processing page (\d+)/);
        if (pageMatch) {
            session.currentPage = parseInt(pageMatch[1]);
        }
        
        // Captcha detection
        if (line.includes('captcha') || line.includes('Captcha') || 
            line.includes('Please enter the captcha text')) {
            session.needsCaptcha = true;
        }
        
        if (line.includes('Captcha entered') || line.includes('✅ Captcha entered')) {
            session.needsCaptcha = false;
            session.captchaError = null;
        }
        
        if (line.includes('captcha is incorrect') || line.includes('Invalid captcha') ||
            line.includes('Captcha is incorrect')) {
            session.needsCaptcha = true;
            session.captchaError = 'Captcha is incorrect. Please try again.';
        }
        
        // Completion detection
        if (line.includes('Scraping completed') || line.includes('🎉 Scraping completed')) {
            session.logs.push(`✅ Scraping completed successfully for ${session.config.stateName}!`);
            
            // Trigger database save
            if (session.folderName && session.config) {
                saveTendersToDatabase(session.folderName, session.config, configId);
            } else {
                console.log(`[${configId}] No folder name captured, skipping database save`);
            }
        }
    });
    
    if (session.logs.length > 150) {
        session.logs = session.logs.slice(-150);
    }
}

// Save tenders to database via API
async function saveTendersToDatabase(folderName, config, configId) {
    const session = scrapingSessions[configId];
    if (!session) return;
    
    try {
        session.logs.push('📤 Saving scraped data to database...');
        console.log(`[${configId}] Calling API for folder: ${folderName}`);

        const rootPath = '/var/www/html/eprocure/kerala/downloads';
        const fullPath = `${rootPath}/${config.sourceCode}`;  // Add this line

        const data = JSON.stringify({
            "startDate": "",
            "endDate": "",
            "keyword": "",
            "source": config.sourceCode,
            "path": fullPath,  // Change from config.docPath to fullPath
            "dateFolders": [folderName]
        });

        console.log('=== API CALL DEBUG ===');
        console.log('Source:', config.sourceCode);
        console.log('Full Path:', fullPath);
        console.log('Folder Name:', folderName);
        console.log('Complete Request:', data);
        console.log('======================');

        const response = await axios.post(
            'https://app.minaions.com:1590/internal-api/run-tender-discovery-by-date',
            data,
            {
                headers: {
                    'x-internal-api-key': 'J5sR0hKqS9MtA3Xg',
                    'Content-Type': 'application/json'
                },
                timeout: 10800000
            }
        );
        
        session.logs.push('✅ Database save successful!');
        session.logs.push(`📊 API Response: ${JSON.stringify(response.data)}`);
        session.logs.push('🏁 All processes completed!');
        
        console.log(`[${configId}] Database save successful`);
        
    } catch (error) {
        console.error(`[${configId}] Database save error:`, error.message);
        session.logs.push(`❌ Database save failed: ${error.message}`);
        
        if (error.response) {
            session.logs.push(`📄 API Error: ${JSON.stringify(error.response.data)}`);
        }
    }
}

// Cleanup session
function cleanupSession(configId) {
    const session = scrapingSessions[configId];
    if (!session) return;
    
    console.log(`Cleaning up session: ${configId}`);
    
    if (session.process) {
        try {
            if (!session.process.killed) {
                session.process.kill('SIGTERM');
            }
        } catch (err) {
            console.log(`[${configId}] Process already terminated`);
        }
    }
    
    session.isRunning = false;
    session.needsCaptcha = false;
    session.captchaError = null;
    session.process = null;
    
    console.log(`[${configId}] Session cleanup completed`);
}

// Utility functions
function generateSessionId() {
    return Math.random().toString(36).substring(2, 15) + Date.now().toString(36);
}

function getUptime(startTime) {
    if (!startTime) return '0s';
    const seconds = Math.floor((Date.now() - startTime) / 1000);
    if (seconds < 60) return `${seconds}s`;
    const minutes = Math.floor(seconds / 60);
    if (minutes < 60) return `${minutes}m ${seconds % 60}s`;
    const hours = Math.floor(minutes / 60);
    return `${hours}h ${minutes % 60}m`;
}

// Graceful shutdown
process.on('SIGINT', () => {
    console.log('Shutting down server...');
    Object.keys(scrapingSessions).forEach(configId => {
        cleanupSession(configId);
    });
    process.exit(0);
});

process.on('SIGTERM', () => {
    console.log('Server terminated');
    Object.keys(scrapingSessions).forEach(configId => {
        cleanupSession(configId);
    });
    process.exit(0);
});

// Start server
app.listen(PORT, '0.0.0.0', () => {
    console.log(`Multi-Config Tender Scraper Dashboard running on http://localhost:${PORT}`);
    console.log(`Access from network: http://YOUR_SERVER_IP:${PORT}`);
});
