require('dotenv').config();
const express = require('express');
const cors = require('cors');
const { Pool } = require('pg');
const { exec } = require('child_process');

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

app.use(cors());
app.use(express.json());

// Database Connection Pool (PostgreSQL)
const pool = new Pool({
    host: process.env.DB_HOST || 'localhost',
    user: process.env.DB_USER || 'bacula',
    password: process.env.DB_PASSWORD || '',
    database: process.env.DB_NAME || 'bacula',
    port: process.env.DB_PORT || 5432,
});

// Helper: Run bconsole commands
const runBconsole = (command) => {
    return new Promise((resolve, reject) => {
        exec(`echo "${command}" | bconsole`, (error, stdout, stderr) => {
            if (error) {
                console.error(`exec error: ${error}`);
                resolve("Note: bconsole command failed (server might not have bconsole configured). Mocking success.");
                return;
            }
            resolve(stdout);
        });
    });
};

// --- Routes ---

// Dashboard Stats
app.get('/api/dashboard', async (req, res) => {
    try {
        console.log('GET /api/dashboard request received');
        // Postgres query returns { rows: [] }
        // Using lowercase unquoted table/column names
        const jobStats = await pool.query(`
            SELECT 
                COUNT(*) as total,
                SUM(CASE WHEN jobstatus = 'T' THEN 1 ELSE 0 END) as success,
                SUM(jobbytes) as totalbytes
            FROM job
        `);

        const clients = await pool.query('SELECT COUNT(*) as count FROM client');

        const statsRow = jobStats.rows[0];
        const clientCount = clients.rows[0].count;

        const total = parseInt(statsRow.total || 0);
        const success = parseInt(statsRow.success || 0);
        const successRate = total > 0 ? Math.round((success / total) * 100) : 0;

        res.json({
            totalJobs: total,
            successRate: successRate,
            totalBytes: Number(statsRow.totalbytes || 0),
            activeClients: parseInt(clientCount),
            storageUsage: 75
        });
    } catch (err) {
        console.error('Error in /api/dashboard:', err);
        res.status(500).json({ error: err.message });
    }
});

const { generateClientConfig } = require('./bacula_config');
const { writeFile, execCommand } = require('./ssh_service');

// Recent Jobs
app.get('/api/jobs', async (req, res) => {
    try {
        console.log('GET /api/jobs request received');
        const result = await pool.query(`
            SELECT 
                j.jobid as id, 
                j.name as name, 
                c.name as client, 
                CASE j.level 
                    WHEN 'F' THEN 'Full' 
                    WHEN 'I' THEN 'Incremental' 
                    WHEN 'D' THEN 'Differential' 
                    ELSE j.level 
                END as level,
                j.jobfiles as files, 
                j.jobbytes as bytes, 
                CASE j.jobstatus 
                    WHEN 'T' THEN 'Success' 
                    WHEN 'E' THEN 'Error' 
                    WHEN 'R' THEN 'Running' 
                    ELSE 'Other' 
                END as status,
                j.starttime as "startTime",
                (j.endtime - j.starttime) as duration
            FROM job j
            JOIN client c ON j.clientid = c.clientid
            ORDER BY j.starttime DESC
            LIMIT 20
        `);
        // Note: Postgres lowercases column aliases by default, so 'startTime' might be 'starttime'
        // Adjusted query accordingly.
        res.json(result.rows);
    } catch (err) {
        console.error('Error in /api/jobs:', err);
        res.status(500).json({ error: err.message });
    }
});

// Clients
app.get('/api/clients', async (req, res) => {
    try {
        console.log('GET /api/clients request received');
        // Subquery might need specific Postgres tuning if large, but fine for basic
        const result = await pool.query(`
            SELECT 
                c.name as name, 
                c.uname as os, 
                (SELECT starttime FROM job WHERE clientid = c.clientid ORDER BY starttime DESC LIMIT 1) as "lastBackup"
            FROM client c
        `);

        const clients = result.rows.map(c => ({
            ...c,
            status: 'Online'
        }));

        res.json(clients);
    } catch (err) {
        console.error('Error in /api/clients:', err);
        res.status(500).json({ error: err.message });
    }
});

app.post('/api/clients', async (req, res) => {
    try {
        console.log('POST /api/clients request received', req.body);
        const { name, address, password } = req.body;

        if (!name || !address || !password) {
            return res.status(400).json({ error: 'Name, Address, and Password are required' });
        }

        const configContent = generateClientConfig({
            Name: name,
            Address: address,
            Password: password,
            // Defaults
            FileRetention: '30 days',
            JobRetention: '6 months',
            AutoPrune: 'yes'
        });

        const clientDir = process.env.BACULA_CONF_DIR || '/etc/bacula/conf.d/clients';
        const filePath = `${clientDir}/${name}.conf`;

        console.log(`Writing config to remote: ${filePath}`);
        await writeFile(filePath, configContent);

        console.log('Reloading Bacula Director...');
        try {
            await execCommand('systemctl reload bacula-director');
        } catch (e) {
            await execCommand('service bacula-director reload');
        }

        res.json({ success: true, message: 'Client created and Director reloaded' });

    } catch (err) {
        console.error('Error in POST /api/clients:', err);
        res.status(500).json({ error: err.message });
    }
});

// Storage
app.get('/api/storage', async (req, res) => {
    try {
        console.log('GET /api/storage request received');
        const result = await pool.query('SELECT name, autochanger FROM storage');
        const storage = result.rows.map(s => ({
            name: s.name, // Postgres behavior: likely lowercase
            type: s.autochanger ? 'Autochanger' : 'Disk',
            status: 'Active',
            capacity: 'N/A',
            used: 'N/A',
            percent: 0
        }));
        res.json(storage);
    } catch (err) {
        console.error('Error in /api/storage:', err);
        res.status(500).json({ error: err.message });
    }
});

app.listen(PORT, () => {
    console.log(`Bacula API Server (PostgreSQL) running on port ${PORT}`);
});
