import express from "express";
import mustache from "mustache";
import bodyParse from "body-parser";
import { readdirSync, readFileSync } from "fs";
import { MongoClient } from "mongodb";
import { ObjectId } from "mongodb";

const app = express();
app.use(express.static("./static"));
app.use(bodyParse.urlencoded({ extended: true }));
app.use(bodyParse.json());
const port = 9889;

const templates = new Map(readdirSync("./templates").map(fn => [fn, readFileSync(`./templates/${fn}`, "utf-8")]));

/** @type {MongoClient} */
const client = await MongoClient.connect("mongodb://127.0.0.1:27017/weit_db?directConnection=true&serverSelectionTimeoutMS=2000&appName=weit");
const announcements = client.db().collection("announcements");
try { await announcements.createIndex({ text: "text" }); } catch (e) { }

app.get("/", (req, res) => {
    res.send(mustache.render(templates.get("mainPage.html")));
});

app.get("/createAnnouncement", (req, res) => {
    res.send(mustache.render(templates.get("createAnnouncementPage.html")));
});

app.get("/:announcementID", (req, res) => {
    res.send(mustache.render(templates.get("announcementPage.html"), { anid: req.params.announcementID }));
});

app.get("/api/announcements", async (req, res) => {
    res.send({
        count: await announcements.countDocuments(),
        announcements: await (async () => {
            let out = [];
            await announcements.find().forEach(anmnt => out.push(anmnt));
            return out;
        })()
    });
});

app.get("/api/announcement/:announcementID", async (req, res) => {
    let announcement = { ok: false };
    try {
        announcement = await announcements.findOne({ _id: ObjectId(req.params.announcementID) });
        announcement.ok = true;
    } catch (e) { console.error(e); }

    res.send(announcement);
});

app.put("/api/announcement", async (req, res) => {
    const { title, text, phone } = req.body;
    let result = { ok: false };
    if (title === undefined || text === undefined || phone === undefined) {
        result["error"] = "Empty input data!";
    } else {
        result["announcementId"] = (await announcements.insertOne({
            title, text, phone
        })).insertedId;
        result.ok = true;
    }
    res.send(result);
});

app.delete("/api/announcements/:announcementID", async (req, res) => {
    let result = { ok: false };
    try {
        result = await announcements.deleteOne({ _id: ObjectId(req.params.announcementID) });
        result.ok = true;
    } catch (e) { console.error(e); result["error"] = `Exception: ${e}`; }

    res.send(result);
});

app.patch("/api/announcements/:announcementID", async (req, res) => {
    let result = { ok: false };
    const { title, text, phone } = req.body;
    if (title === undefined && text === undefined && phone === undefined) {
        result["error"] = "Empty input data!";
    } else {
        try {
            let mod = {};
            if (title) {
                mod["title"] = title;
            }
            if (text) {
                mod["text"] = text;
            }
            if (phone) {
                mod["phone"] = phone;
            }
            await announcements.updateOne({ _id: ObjectId(req.params.announcementID) }, { $set: mod });
            result.ok = true;
        } catch (e) { console.error(e); result["error"] = `Exception: ${e}`; }
    }

    res.send(result);
});

app.post("/api/search", async (req, res) => {
    let result = { ok: false };
    const { text } = req.body;
    if (text === undefined) {
        result["error"] = "Empty search!";
    } else {
        try {
            let searchResults = await (async () => {
                let out = [];
                await announcements.find({ $text: { $search: text } }).forEach(anmnt => out.push(anmnt));
                return out;
            })();
            result["result"] = searchResults;
            result.ok = true;
        } catch (e) { console.error(e); result["error"] = `Exception: ${e}`; }
    }

    res.send(result);
});

app.listen(port, () => console.log(`⚡️ Serving on port ${port}`));