import fs from 'fs';
import https from 'https';
import { exec } from 'child_process';
import chokidar from 'chokidar';
import path from 'path';
import util from 'util';

// Determine the environment
const environment = process.env.NODE_ENV || 'development';
const configFile = `config_${environment}.json`;

// Load the appropriate configuration
let config;
try {
    config = JSON.parse(fs.readFileSync(path.resolve('../', configFile), 'utf8'));
} catch (error) {
    console.error(`โŒ Error reading configuration file: ${error.message}`);
    process.exit(1);
}

const OPENAPI_URL = config.OPENAPI_URL;
const SCHEMA_PATH = path.resolve(config.SCHEMA_PATH);
const OUTPUT_DIRECTORY = path.resolve(config.OUTPUT_DIRECTORY);
const SSL_KEY_PATH = path.resolve(config.SSL_KEY_PATH);
const SSL_CERT_PATH = path.resolve(config.SSL_CERT_PATH);

console.log(`Using SCHEMA_PATH: ${SCHEMA_PATH}`);
console.log(`Using OUTPUT_DIRECTORY: ${OUTPUT_DIRECTORY}`);

const execPromisified = util.promisify(exec);

let isGenerating = false;
const debounceDelay = 500;  // 500ms debounce

function debounce(func, delay) {
    let timer;
    return (...args) => {
        clearTimeout(timer);
        timer = setTimeout(() => {
            func.apply(this, args);
        }, delay);
    };
}

async function fetchAndGenerate() {
    if (isGenerating) {
        console.log("โš ๏ธ Generation is already running.");
        return;
    }
    isGenerating = true;

    console.log("๐Ÿš€ Fetching OpenAPI schema...");

    try {
        const options = {
            rejectUnauthorized: false,
            key: fs.readFileSync(SSL_KEY_PATH),
            cert: fs.readFileSync(SSL_CERT_PATH),
        };

        const res = await new Promise((resolve, reject) => {
            https.get(OPENAPI_URL, options, resolve).on('error', reject);
        });

        let data = '';
        res.on('data', (chunk) => {
            data += chunk;
        });

        res.on('end', async () => {
            try {
                fs.writeFileSync(SCHEMA_PATH, data, 'utf8');
                console.log(`โœ… OpenAPI schema saved to ${SCHEMA_PATH}`);
            } catch (writeError) {
                console.error(`โŒ Error saving OpenAPI schema: ${writeError}`);
                isGenerating = false;
                return;
            }

            console.log("๐Ÿงผ Cleaning output directory...");
            try {
                await fs.promises.rm(OUTPUT_DIRECTORY, { recursive: true, force: true });
                console.log(`โœ… Output directory cleaned at ${OUTPUT_DIRECTORY}`);

                if (fs.existsSync(OUTPUT_DIRECTORY)) {
                    console.error(`โŒ Output directory still exists: ${OUTPUT_DIRECTORY}`);
                } else {
                    console.log(`โœ… Confirmed removal of ${OUTPUT_DIRECTORY}`);
                }

                const command = `npx openapi -i ${SCHEMA_PATH} -o ${OUTPUT_DIRECTORY}`;
                console.log(`Executing debug command: ${command}`);

                const { stdout, stderr } = await execPromisified(command);
                if (stderr) {
                    console.error(`โš ๏ธ stderr while generating services: ${stderr}`);
                } else {
                    console.log(`โœ… Command executed successfully, output:\n${stdout}`);
                }
            } catch (error) {
                console.error(`โŒ Error cleaning or executing command: ${error}`);
            }

            isGenerating = false;
        });
    } catch (error) {
        console.error('โŒ Error fetching OpenAPI schema: ' + error.message);
        isGenerating = false;
    }
}

const backendDirectory = path.resolve('/Users/gotthardg/PycharmProjects/heidi-v2/backend/app');
console.log(`๐Ÿ‘€ Watching for changes in ${backendDirectory}`);
const watcher = chokidar.watch(backendDirectory, { persistent: true, ignored: [SCHEMA_PATH, OUTPUT_DIRECTORY] });

watcher
    .on('add', debounce(fetchAndGenerate, debounceDelay))
    .on('change', debounce(fetchAndGenerate, debounceDelay))
    .on('unlink', debounce(fetchAndGenerate, debounceDelay));

console.log(`๐Ÿ‘€ Watching for changes in ${backendDirectory}`);