module api_modules.announcement;

import handy_httpd;
import handy_httpd.handlers.path_handler;
import slf4d;
import ddbc;

import db;
import data_utils;
import api_modules.auth : getAdminUserOrThrow;

struct Announcement {
    const ulong id;
    const string type;
    const string message;

    static Announcement parse(DataSetReader r) {
        return Announcement(
            r.getUlong(1),
            r.getString(2),
            r.getString(3)
        );
    }
}

void registerApiEndpoints(PathHandler handler) {
    handler.addMapping(Method.GET, "api/announcement", &getAnnouncementsEndpoint);
    handler.addMapping(Method.POST, "api/announcement", &createAnnouncementAdminEndpoint);
    handler.addMapping(Method.DELETE, "api/announcement/:id:ulong", &deleteAnnouncementAdminEndpoint);
}

void getAnnouncementsEndpoint(ref HttpRequestContext ctx) {
    Connection conn = getDb();
    scope(exit) conn.close();
    const announcements = findAll(
        conn,
        "SELECT * FROM announcement ORDER BY id DESC",
        &Announcement.parse
    );
    writeJsonBody(ctx, announcements);
}

void createAnnouncementAdminEndpoint(ref HttpRequestContext ctx) {
    Connection conn = getDb();
    scope(exit) conn.close();
    auto user = getAdminUserOrThrow(ctx, conn);
    struct Payload {
        string type;
        string message;
    }
    Payload payload = readJsonPayload!(Payload)(ctx);
    if (payload.type is null || (payload.type != "INFO" && payload.type != "ERROR")) {
        ctx.response.status = HttpStatus.BAD_REQUEST;
        ctx.response.writeBodyString("Invalid type.");
        return;
    }
    if (payload.message is null || payload.message.length < 1 || payload.message.length > 2000) {
        ctx.response.status = HttpStatus.BAD_REQUEST;
        ctx.response.writeBodyString("Invalid message.");
        return;
    }
    ulong id = insertOne(
        conn,
        "INSERT INTO announcement (type, message) VALUES (?, ?) RETURNING id",
        payload.type, payload.message
    );
    const announcement = findOne(
        conn,
        "SELECT * FROM announcement WHERE id = ?",
        &Announcement.parse,
        id
    ).orElseThrow();
    writeJsonBody(ctx, announcement);
}

void deleteAnnouncementAdminEndpoint(ref HttpRequestContext ctx) {
    Connection conn = getDb();
    scope(exit) conn.close();
    auto user = getAdminUserOrThrow(ctx, conn);
    ulong id = ctx.request.getPathParamAs!ulong("id");
    update(conn, "DELETE FROM announcement WHERE id = ?", id);
}