const fs = require('fs/promises');
const { createReadStream } = require('fs');
const path = require('path');
const readline = require('readline/promises');
// const { info } = require('console');

async function readFirstLines(filePath, lineCount = 1) {
    return new Promise((resolve, reject) => {
        try {
            const stream = createReadStream(filePath, { encoding: 'utf-8' });
            const rl = readline.createInterface({ input: stream });
            let counter = 0;
            const lines = [];
            rl.on('line', (line) => {
                counter++;
                lines.push(line);
                if (counter >= lineCount) {
                    rl.close();
                    rl.removeAllListeners();
                }
            });
            rl.on('close', () => {
                resolve(lines)
            });
        } catch (e) {
            reject(e)
        }
    });
}

async function getTitle(filePath) {
    const firstLines = await readFirstLines(filePath);
    if (firstLines === undefined || firstLines.length === 0)
        return null;
    let title = firstLines[0];
    if (title.substring(0, 2) !== '# ')
        return null;
    title = title
        .substring(1, firstLines[0].length)
        .trim();
    if (title.length < 3)
        return null;
    return title;
}

async function getMarkdownMetadata(dir) {
    const dirPath = path.join(process.cwd(), dir);
    const files = (await fs.readdir(dirPath, 'utf-8'))
        .filter((file) => {
            return /^[^.].*.md$/.test(file);
        })


    const out = {};
    for (const file of files) {
        const filePath = path.join(dirPath, file);
        const title = await getTitle(filePath);
        if (title === null)
            continue;

        const slug = file.replace(/\.md$/, '');
        // const pagePath = path.join('/', dir, slug);
        out[slug] = {
            title: title,
            // path: pagePath,
            mtime: (await fs.stat(filePath)).mtime,

        };
    }
    return out;
}

async function readFilesMetadata(dir) {
    const filePath = jsonFilePath(dir);
    try {
        const fileContent = await fs.readFile(filePath, 'utf-8');
        const metadata = JSON.parse(fileContent);
        return metadata;
    } catch {
        return [];
    }
}

async function writeFilesMetadata(filePath, metadata) {
    try {
        await fs.writeFile(filePath, JSON.stringify(metadata), 'utf-8');
    } catch (error) {
        console.error(error);
    }
}

function jsonFilePath(dir) {
    return path.join(process.cwd(), 'public', `${dir}.json`);
}

async function generateNotesMetadata() {
    const dir = 'notes';
    await writeFilesMetadata(jsonFilePath(dir), await getMarkdownMetadata(dir));
}

async function generatePostsMetadata() {
    const dir = 'posts';
    const currMetadata = await readFilesMetadata(dir);
    const generatedMetadata = await getMarkdownMetadata(dir);
    const newMetadata = {};

    for (const [name, data] of Object.entries(generatedMetadata)) {
        let otime;
        if (currMetadata[name] !== undefined && currMetadata[name].otime !== undefined)
            otime = currMetadata[name].otime
        else
            otime = data.mtime;

        newMetadata[name] = { ...data, otime }
    }
    await writeFilesMetadata(jsonFilePath(dir), newMetadata);
}

async function generateSiteMap() {
    await generateNotesMetadata();
    await generatePostsMetadata();

    const sitemap = {
        title: 'PaulW.XYZ',
        subpages: await readFilesMetadata('home')
    };

    const pages = ['posts', 'notes'];
    for (const page of pages) {
        sitemap.subpages[page].subpages = await readFilesMetadata(page);
    }

    await writeFilesMetadata(jsonFilePath('sitemap'), sitemap);
}

generateSiteMap();
