const db = require('../models');
const { logger } = require('nodejs-log-agent');
const fs = require('fs').promises; // Import fs.promises for async file operations
const cronJob = require('../libs/cronJob'); // Import cronJob module
const moment = require('moment'); // Import moment for date calculations

const checkHealth = async (req, res) => {
    const checks = {};
    let httpStatus = 200;
    let overallStatus = 'ok';

    // Helper untuk memperbarui status keseluruhan dan HTTP
    const updateOverallStatus = (checkStatus) => {
        if (checkStatus === 'error') { // Jika ada satu saja error, status keseluruhan adalah 'error'
            overallStatus = 'error';
        } else if (checkStatus === 'warn' && overallStatus === 'ok') { // Jika tidak ada error, tapi ada warning, status keseluruhan adalah 'warn'
            overallStatus = 'warn'; // Jika ada warning tapi belum ada error
            // httpStatus tetap 200 untuk warning, tapi overallStatus mencerminkan ini
        }
    };

    // 1. Cek Koneksi Database
    try {
        await db.sequelize.authenticate();
        checks.database = 'ok';
        logger.info('[Health Check] Database connection successful.');
    } catch (error) {
        checks.database = 'error';
        logger.error('[Health Check] Database connection failed.', { 
            message: error.message, 
            stack: error.stack 
        });
        updateOverallStatus('error');
    }

    // 2. Cek Izin Tulis ke Direktori PDF
    const pdfDirectory = './public/invoice'; // Sesuaikan dengan path direktori PDF Anda
    try {
        // Coba membuat file sementara dan menghapusnya untuk memverifikasi izin tulis
        const testFilePath = `${pdfDirectory}/.healthcheck_test`;
        await fs.mkdir(pdfDirectory, { recursive: true }); // Pastikan direktori ada
        await fs.writeFile(testFilePath, 'health check test', 'utf8');
        await fs.unlink(testFilePath);
        checks.pdfWritePermission = 'ok';
        logger.info(`[Health Check] PDF directory '${pdfDirectory}' is writable.`);
    } catch (error) {
        checks.pdfWritePermission = 'error';
        logger.error(`[Health Check] PDF directory '${pdfDirectory}' is not writable.`, {
            message: error.message,
            stack: error.stack
        });
        updateOverallStatus('error');
    }

    // 3. Cek Status Cron Job
    try {
        const cronIsRunning = cronJob.getStatus(); // Actual state of the node-cron scheduler
        const cronDesiredState = cronJob.getDesiredState(); // Intended state (user's preference)
        const cronTimestamps = cronJob.getTimestamps();
        checks.cronJob = {
            running: cronIsRunning,
            desired: cronDesiredState, // Add desired state to health check output
            lastRun: cronTimestamps.lastRun,
            nextRun: cronTimestamps.nextRun
        };

        if (!cronIsRunning && cronDesiredState) {
            // Cron is not running, but it *should* be running (desired state is true).
            // This indicates an unexpected stop. The internal monitor should handle the restart.
            checks.cronJob.status = 'error';
            logger.error('[Health Check] Cron Job is not running but desired state is active. Waiting for internal monitor to recover.');
            updateOverallStatus('error');
        } else if (!cronIsRunning && !cronDesiredState) {
            // Cron is not running, and it's intentionally stopped by user.
            checks.cronJob.status = 'stopped_intentionally';
            logger.info('[Health Check] Cron Job is intentionally stopped.');
            // No updateOverallStatus needed, as it's an expected state.
        } else if (cronIsRunning) {
            // Cron is running. Now check if it has executed recently.
            if (cronTimestamps.lastRun) {
                const lastRunMoment = moment(cronTimestamps.lastRun, 'YYYY-MM-DD HH:mm:ss'); // Parse with format
                const nowMoment = moment();
                const minutesSinceLastRun = nowMoment.diff(lastRunMoment, 'minutes');

                // Assuming cron runs every minute. If last run was more than 2 minutes ago, it's a warning.
                if (minutesSinceLastRun > 2) {
                    checks.cronJob.status = 'warn';
                    logger.warn(`[Health Check] Cron Job is running but last run was ${minutesSinceLastRun} minutes ago.`);
                    updateOverallStatus('warn');
                } else {
                    checks.cronJob.status = 'ok';
                    logger.info('[Health Check] Cron Job is running and recently executed.');
                }
            } else {
                // Cron is running but has never executed (e.g., just started, first run pending).
                checks.cronJob.status = 'ok'; // Or 'warn' if it's expected to have run by now
                logger.info('[Health Check] Cron Job is running but has not executed yet (first run pending).');
            }
        } else {
            // Fallback for any unhandled state (should ideally not be reached with the above logic)
            checks.cronJob.status = 'error';
            logger.error('[Health Check] Unexpected Cron Job state encountered.');
            updateOverallStatus('error');
        }
    } catch (error) {
        checks.cronJob = { status: 'error', message: error.message };
        logger.error('[Health Check] Error checking Cron Job status.', { message: error.message, stack: error.stack });
        updateOverallStatus('error');
    }

    // 4. Cek Konfigurasi Environment Variables Kritis
    const criticalEnvVars = [
        'API_URL', // Untuk link PDF di pesan WhatsApp
        'WA_API_URL', 'WA_ACCESS_TOKEN' // Untuk pengiriman pesan WhatsApp oleh cron job
    ];
    checks.envVariables = {};
    let envVarStatus = 'ok';

    for (const envVar of criticalEnvVars) {
        if (!process.env[envVar]) {
            checks.envVariables[envVar] = 'missing';
            // Menganggap missing env var sebagai warning, karena aplikasi mungkin masih bisa start
            // tapi fungsionalitas terkait akan gagal.
            envVarStatus = 'warn'; 
            logger.warn(`[Health Check] Critical environment variable '${envVar}' is missing.`);
        } else {
            checks.envVariables[envVar] = 'set';
        }
    }

    if (envVarStatus === 'warn') {
        checks.envVariables.overall = 'warn';
        updateOverallStatus('warn');
    } else {
        checks.envVariables.overall = 'ok';
    }

    return res.status(200).json({ // Selalu kembalikan HTTP status 200 OK
        status: overallStatus,
        timestamp: new Date().toISOString(),
        checks: checks,
        // Optionally, if overallStatus is 'warn' or 'error', you might want to return a different HTTP status
        // However, the current code explicitly returns 200. Sticking to that.
    });
};

module.exports = {
    checkHealth,
};