const path = require('path')
const fs = require('fs/promises')

const gitRef = process.env.WWW_GIT_REF ?? 'master'
const giteaApiRepo = `https://git.paulw.xyz/api/v1/repos/xyz/www/` 

async function readFirstLines(filePath, lineCount = 1) {
    const gitFileFetch = await fetch(`${giteaApiRepo}raw/${filePath}?ref=${gitRef}`)
    if (!gitFileFetch.ok) return null
    const file = await gitFileFetch.text()
    const lines = file.split('\n')
    const out = []
    for (let i = 0; i < lineCount && i < lines.length; i++) {
        out.push(lines[i])
    }
    return out
}

async function getTitle(filePath) {
    const firstLines = await readFirstLines(filePath)
    if (firstLines === null || 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 dirGitInfoFetch = await fetch(`${giteaApiRepo}contents/${dir}/?ref=${gitRef}`)
    if (!dirGitInfoFetch.ok) return {}

    const commits = {}
    const out = {}

    const dirGitInfo = await dirGitInfoFetch.json()
    for (const file of dirGitInfo) {
        if (file.name.startsWith('.') || !file.name.endsWith('.md')) continue
        const title = await getTitle(file.path)
        if (title === null) continue

        const slug = file.name.replace(/\.md$/, '')
        let mtime = new Date(); // better to have an incorrect recent date than the more incorrect unix time 0 (assuming the host doesn't have messed up clock)


        if (!(file.last_commit_sha in commits)) {
            const lastCommitSha = await fetch(`${giteaApiRepo}/git/commits/${file.last_commit_sha}`)
            if (lastCommitSha.ok) {
                const commitJson = await lastCommitSha.json()
                commits[commitJson.sha] = (new Date(commitJson.created))
            }
        }

        mtime = commits[file.last_commit_sha]

        out[slug] = {
            title: title,
            mtime: mtime.toISOString(),
        }
    }
    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, null, 4), 'utf-8')
    } catch (error) {
        console.error(error)
    }
}

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

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 = new Date()
        if (currMetadata[name]?.otime !== undefined && currMetadata[name]?.otime !== null)
            otime = currMetadata[name].otime ?? otime
        else
            otime = data.mtime ?? otime

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

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

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

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

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

generateSiteMap()
