import "../styles/style.scss";
import {moduleId} from "./constants";
import {DiceTower} from "./types";
import {Customization} from "./apps/customization";
import {DiceSocket} from "./apps/diceSocket";
import {getSetting, registerSetting, setSetting} from "./apps/utils";
import {Service} from "./apps/service";
import {Overlays} from "./apps/overlays";

let module: DiceTower;

Hooks.once("init", async () => {
    module = (game as Game).modules.get(moduleId) as unknown as DiceTower;
    module.log = (message) => console.log(`Dice-Tower | `, message)
    module.log("Initialized")
    module.customization = new Customization()
    module.overlays = new Overlays()
    module.diceSocket = new DiceSocket()
    module.service = new Service()
    registerSettings()
});

Hooks.on("renderChatLog", async (_: Application, _html: JQuery): Promise<void> => {
    module.log("Rendering Controls")
    module.controls = $(await renderTemplate(`modules/${moduleId}/templates/dice-tower-controls.hbs`, {}))
    await renderDiceTowerControls(new Map([
        ...(new Map(
            ["d4", "d6", "d8", "d10", "d12", "d20", "d100"]
                .map(dice => [`dice-tower-roll-${dice}`, (controls: JQuery) => {
                    roll(controls.find(`#dice-tower-amount`), dice)
                }]))),
        ...(new Map([
            ["dice-tower-sheet", (_: JQuery) => {
                openSheet()
            }],
            ["dice-tower-customize", (_: JQuery) => {
                module.customization.render(true)
            }],
            ["dice-tower-urls", (_: JQuery) => {
                module.overlays.render(true)
            }],
            ["dice-tower-remove-dice", (controls: JQuery) => {
                removeDice(controls.find("#dice-tower-amount"))
            }],
            ["dice-tower-add-dice", (controls: JQuery) => {
                addDice(controls.find("#dice-tower-amount"))
            },
            ]]
        ))]
    ));
    module.log("Render complete")
});

Hooks.once("ready", () => {
    fillActors();
    module.service.register()
})

Hooks.on("preCreateChatMessage", (message: ChatMessage): void => {
    if (message.isRoll && getSetting("sendToDiceTower") as Boolean) {
        let results = []
        let command = "";
        message.rolls.forEach(roll => {
            let sides
            let modifier = 0
            let modifierMultiplikator = 1
            let rolls: {value: number}[] = []
            roll.terms.forEach(term => {
                if (term instanceof foundry.dice.terms.Die) {
                    let t = term as foundry.dice.terms.Die;
                    sides = t.faces
                    let c = t.number + 'd' + sides;
                    if (command.length > 0) {
                        command = [command, c].join(" ")
                    } else {
                        command = c
                    }
                    t.results.map(it => {
                        return {value: it.result}
                    }).forEach(it => rolls.push(it))
                }
                if (term instanceof foundry.dice.terms.OperatorTerm ) {
                    let t = term as foundry.dice.terms.OperatorTerm
                    if (t.operator === '+') {
                        modifierMultiplikator = 1
                    } else if (t.operator === '-') {
                        modifierMultiplikator = -1
                    }
                }
                if (term instanceof foundry.dice.terms.NumericTerm) {
                    let t = term as foundry.dice.terms.NumericTerm
                    modifier += t.number * modifierMultiplikator
                }
            });
            results.push({
                sides: sides,
                modifier: modifier,
                value: roll.total,
                rolls: rolls
            })
            module.service.roll({
                name: message.alias,
                command: command,
                results: results
            })
        })
    }
})

Hooks.on("updateUser", (_user, _character: {character: string}, _time, _id) => {
    fillActors();
})

function registerSettings() {
    game.settings?.registerMenu(moduleId, "overlays", {
        name: "DICETOWER.overlaysTitle",
        label: "DICETOWER.overlaysTitle",
        type: Overlays,
        icon: "fas fa-link"
    })
    setSetting("default-dice", {
        theme: 'none',
        faceColor: '#8d8981',
        numberColor: '#000000'
    }, true)
    registerSetting("sendToDiceTower", false, {scope: "world", config: true})
    registerSetting("diceTowerUrl", "https://dice-tower.com", {scope: "world", config: true})
    registerSetting("diceTowerRoom", "", {scope: "world", config: true})
}

function openSheet() {
    let actorId = module.controls.find('#dice-tower-actor').val();
    if (actorId) {
        let actor = game.actors?.get(actorId as string);
        if (actor) {
            Hotbar.toggleDocumentSheet(actor.uuid);
        }
    }
}

function fillActors() {
    let actors = module.controls.find("#dice-tower-actor");
    actors.empty()
    if (game.user?.character) {
        actors.append($(`<option value="${game.user?.character?.id}" selected>${game.user?.character?.name}</option>`));
    } else {
        actors.append($(`<option value="${game.user?.id}" selected>${game.user?.name}</option>`));
    }
    if (game.user?.isGM) {
        let optionGroups = new Map<string, JQuery>
        game.actors?.forEach(e => {
            let actor = e as foundry.documents.BaseActor;
            if (actor.folder) {
                if (!optionGroups.has(actor.folder.uuid)) {
                    optionGroups.set(actor.folder.uuid, $(`<optgroup label="${actor.folder.name}"></optgroup>`));
                }
                optionGroups.get(actor.folder.uuid)?.append($(`<option value="${actor.id}">${actor.name}</option>`))
            } else {
                actors.append($(`<option value="${actor.id}">${actor.name}</option>`))
            }
        });
        optionGroups.forEach(value => actors.append(value))
    }
}

async function roll(diceAmount: JQuery, dice: string) {
    new Roll(diceAmount.text() + dice).evaluate().then(roll => roll.toMessage({speaker: {actor: module.controls.find('#dice-tower-actor').val() as string}}));
}

async function renderDiceTowerControls(actions: Map<string, (controls: JQuery) => void>) {
    actions.forEach((value, key) => {
        module.controls.find(`#${key}`).on("click", () => value(module.controls))}
    )
    module.controls.insertAfter("#chat-controls")
}

function addDice(diceAmount: JQuery) {
    let amount = +diceAmount.text()
    diceAmount.text(`${amount + 1}`)
}

function removeDice(diceAmount: JQuery) {
    let amount = +diceAmount.text()
    if (amount > 1) {
        diceAmount.text(`${amount - 1}`)
    }
}
