import {
    MatrixClient,
    SimpleFsStorageProvider,
    AutojoinUpgradedRoomsMixin,
    RichRepliesPreprocessor,
} from "matrix-bot-sdk";

import axios from "axios";

import config from "./config.json" assert {type: "json"};

const homeserverUrl = config.homeserver;
const token = config.token;
const prefix = config.prefix;
const commandsRaw = config.commands;
const rooms = config.rooms;
const doorbellWebhook = config.doorbellWebhook;

function configNotFound(name) {
    throw new Error(`ERROR: Config option "${name}" not found`);
}

if (!homeserverUrl) configNotFound("homeserver");
if (!token) configNotFound("token");
if (!prefix) configNotFound("prefix");
if (!commandsRaw) configNotFound("commands");
if (!rooms) configNotFound("rooms");
if (!doorbellWebhook) configNotFound("doorbellWebhook");

const commands = commandsRaw.map(cmd => cmd.toLowerCase());

// We'll want to make sure the bot doesn't have to do an initial sync every
// time it restarts, so we need to prepare a storage provider. Here we use
// a simple JSON database.
const storage = new SimpleFsStorageProvider("bot-storage.json");

// Now we can create the client and set it up to automatically join rooms.
const client = await new MatrixClient(homeserverUrl, token, storage);
AutojoinUpgradedRoomsMixin.setupOnClient(client);
client.addPreprocessor(new RichRepliesPreprocessor(false));

// We also want to make sure we can receive events - this is where we will
// handle our command.
client.on("room.message", handleCommand);
client.on("room.invite", (roomId) => {
    if (rooms.includes(roomId)) {
        return client.joinRoom(roomId);
    }
});

// Now that the client is all set up and the event handler is registered, start the
// client up. This will start it syncing.
client.start().then(() => console.log("Client started!"));

function noDingDong(client, roomId, event, error) {
    console.log("No ding dong :(");
    console.log(error);
    client.replyNotice(roomId, event, "Couldn't dingdong the doorbell :(");
}

// This is our event handler for dealing with commands.
async function handleCommand(roomId, event) {
    // Don't handle events that don't have contents (they were probably redacted)
    if (!event["content"]) return;

    // Don't handle non-text events
    if (event["content"]["msgtype"] !== "m.text") return;

    // We never send `m.text` messages so this isn't required, however this is
    // how you would filter out events sent by the bot itself.
    if (event["sender"] === await client.getUserId()) return;
    // Make sure that the event looks like a command we're expecting

    // If not in any authorized rooms, ignore
    if (!rooms.includes(roomId)) return;

    // Check that the message starts with the prefix, and get the prefix-less message
    const rawText = event["content"]["body"];
    if (!rawText || !rawText.startsWith(prefix)) return;
    const text = rawText.substring(prefix.length);

    if (commands.some(cmd => text.toLowerCase().startsWith(cmd))) {
        
        fetch(doorbellWebhook, { method: 'POST' }).then(response => {
            if (response.ok) {
                console.log("DING DONG!");
                client.replyNotice(roomId, event, "Doorbell dingdonged!");
            } else {
                noDingDong(client, roomId, event, response);
            }
        }).catch(err => noDingDong(client, roomId, event, err));
    }

    var tags = [];

    var re = /`([a-z1-9:. æøå]*)`/g;
    do {
        var m = re.exec(text);
        if (m) {
            tags.push(m[1]);
        }
    } while (m);

    if (tags == false) return;

    var encoded_tags = encodeURI(JSON.stringify(tags));

    var file_ids = (await axios.get(hydrusURI + "/get_files/search_files?system_inbox=true&tags=" + encoded_tags, {headers: {'Hydrus-Client-API-Access-Key': hydrusToken}})).data.file_ids;

    if (file_ids == false) return;

    console.log(file_ids);

    var random_id = [file_ids[Math.floor(Math.random() * file_ids.length)]];

    var encoded_id = encodeURI(JSON.stringify(random_id));

    var metadata = (await axios.get(hydrusURI + "/get_files/file_metadata?&file_ids=" + encoded_id, {headers: {'Hydrus-Client-API-Access-Key': hydrusToken}})).data.metadata[0];
    console.log(metadata);

    var hash = metadata.hash;
    var width = metadata.width;
    var height = metadata.height;
    var mime = metadata.mime;
    var ext = metadata.ext;
    var size = metadata.size;

    var mxc = "mxc://" + fake_hs + "/" + prefix + hash;

    var event = {
        "body": hash + ext,
        "info": {
            "h": height,
            "w": width,
            "mimetype": mime,
            "size": size,
        },
        "msgtype": "m.image",
        "url": mxc
    };

    client.sendMessage(roomId, event);
}