const fs = require("fs");
const path = require("path");
const { ENOENT, ECONNRESET } = require("constants");

const Koa = require("koa");
const koaPug = require("koa-pug");
const koaRouter = require("koa-router");

const config = require("./config");
const util = require("../shared/util");



const SIZE_UNITS = [ "B", "KiB", "MiB", "GiB" ];

function addFileSizeUnit(size) {
    let i = 0;
    for (; size > 1024; size /= 1024) ++i;
    return [i > 0 ? size.toFixed(2) : size, SIZE_UNITS[i]];
}


function buildCurrentPathLink(path) {
    let currentPath = `<a href="/">root</a>`;

    if (path.endsWith("/"))
        path = path.slice(1, path.length-1);

    const path_parts = path.split("/");

    for (let i = 0; i < path_parts.length; ++i) {
        let lnk = "";

        for (let j = 0; j < i+1; ++j)
            lnk += `/${path_parts[j]}`;

        currentPath += `/<a href="${encodeURI(lnk)}/">${path_parts[i]}</a>`;
    }

    return currentPath;
}

function sortFuncByNameField(a, b) {
    return (a.name > b.name) ? 1 : (a.name < b.name) ? -1 : 0;
}

async function getDirectoryList(dir_path, orig_url) {
    let directories = [];
    let files = [];
    let total_files_size = 0;
    let directory = await fs.promises.opendir(dir_path);

    for await (const dirent of directory) {
        const stat = await fs.promises.stat(path.join(dir_path, dirent.name));
        const [s, u] = addFileSizeUnit(stat.size);

        if (stat.isDirectory())
            directories.push({
                name: dirent.name,
                link: `${encodeURIComponent(dirent.name)}/`,
                datetime: stat.mtime,
                size: "DIR" });
        else {
            total_files_size += stat.size;
            files.push({
                name: dirent.name,
                link: `/files${orig_url}${encodeURIComponent(dirent.name)}`,
                datetime: stat.mtime,
                size: `${s} ${u}` });
        }
    }

    directories.sort(sortFuncByNameField);
    files.sort(sortFuncByNameField);

    return [directories.concat(files), directories.length, files.length,
        addFileSizeUnit(total_files_size).join(' ')];
}

function setRoutes() {
    return koaRouter().get('/(.*)?', async ctx => {
        const file_path = path.join(config.share_path, decodeURI(ctx.originalUrl));

        let stat = await fs.promises.stat(file_path);

        if (stat.isDirectory()) {
            const [items, total_directories, total_files, total_files_size]
                = await getDirectoryList(file_path, decodeURI(ctx.originalUrl));

            await ctx.render('index', {
                clientTZ: util.getClientTimezone(ctx),
                main_site: util.getServiceByHost(ctx.header.host),
                current_path: buildCurrentPathLink(decodeURI(ctx.originalUrl)),
                total_files: total_files,
                total_files_size: total_files_size,
                total_directories: total_directories,
                items: items });
        }
    });
}


const app = new Koa();
const pug = new koaPug({
    viewPath: path.join(__dirname, "views"),
    locals: {
        moment: (date, tz) => util.datetime(date, util.date_formats.file_date, tz), },
    app: app
});

app.proxy = true;
app
    .use(setRoutes().routes())
    // .on("error", err => { if (!err.code == ECONNRESET || !err.code == ENOENT) console.log(err.code); })
    .listen(config.port, config.host);

console.log("Arav's dwelling / Files is up.");