# coding=utf-8
import asyncio
from typing import Optional

# noinspection PyUnresolvedReferences
from js import Event, HTMLInputElement, WebSocket, Sortable, Object
# noinspection PyUnresolvedReferences
from pyodide.ffi import create_proxy, to_js
# noinspection PyUnresolvedReferences
from pyscript import display, document, when

import utils
from strad import event
from strad import util
from strad import view
from strad.util import DE2, GlobalState, clock
from strad.event import StradEventHandler, StradEvent
from strad.view import Strad
from utils import WsWrapper, jsc


GLOBAL_STATE = util.GLOBAL_STATE = utils.GLOBAL_STATE = event.GLOBAL_STATE = view.GLOBAL_STATE = GlobalState()

strad: Optional[Strad] = None
ws: Optional[WsWrapper] = None


def _activate_button(_: Event):
    document.getElementById(DE2.BTN_NEW_GAME_SUBMIT.literal).focus()


def register_listeners(_: Event):
    when('click', DE2.BTN_MENU_NEW_GAME.id)(StradEventHandler.check_new_game)
    when('click', DE2.BTN_CHK_WIN_SUBMIT.id)(StradEventHandler.game.trigger)
    when('click', DE2.BTN_MENU_NEW_PLAYER.id)(StradEventHandler.player.trigger)
    when("click", DE2.BTN_MENU_NEW_MSG.id)(StradEventHandler.message.trigger)
    when('click', DE2.AVAILABLE.id)(StradEventHandler.select)
    when('click', DE2.SELECTED.id)(StradEventHandler.unselect)
    when('click', DE2.BTN_NEW_PLAYER_SUBMIT.id)(StradEventHandler.player.emitter)
    when('click', DE2.BTN_NEW_GAME_SUBMIT.id)(StradEventHandler.game.emitter)
    when('click', DE2.BTN_NEW_MSG_SUBMIT.id)(StradEventHandler.message.emitter)
    when('click', DE2.BTN_CHK_DEL_SUBMIT.id)(StradEventHandler.delete.emitter)
    when('click', DE2.BTN_CANCEL.klass)(StradEventHandler.release_modal_lock)
    when('click', DE2.BTN_OVERVIEW.id)(GLOBAL_STATE.strad.overview.render)
    when('shown.bs.modal', DE2.MODAL_NEW_GAME.id)(_activate_button)

    document.addEventListener(StradEvent.NEW_PLAYER, create_proxy(strad.add_player))
    document.addEventListener(StradEvent.NEW_GAME, create_proxy(strad.add_game))
    document.addEventListener(StradEvent.NEW_MSG, create_proxy(strad.add_msg))
    document.addEventListener(StradEvent.DEL_GAME, create_proxy(strad.delete_game))
    document.addEventListener('keydown', create_proxy(StradEventHandler.call_function))


def populate_dialog(_: Event):
    mode_div = document.getElementById(DE2.GAME_MODE.literal)
    player_div = document.getElementById(DE2.AVAILABLE.literal)
    selected_div = document.getElementById(DE2.SELECTED.literal)
    mode_div.replaceChildren()
    player_div.replaceChildren()
    selected_div.replaceChildren()
    for mode in strad.gamemodes.values():
        for element in mode.disp_form:
            mode_div.appendChild(strad.factory.create(**element))
    selected = strad.gameview.players
    if selected:
        for player in selected.values():
            selected_div.appendChild(strad.factory.create(**player.disp_form))
    for player in strad.players.values():
        if selected and player in selected.values():
            continue
        player_div.appendChild(strad.factory.create(**player.disp_form))
    Sortable.create(selected_div, to_js({'animation': 150, 'ghostClass': 'player-drag-ghost'},
                                        dict_converter=Object.fromEntries))



async def initialize_day(_: Event) -> None:
    global strad

    strad = Strad(wss=ws)
    jsc(f"instantiated {strad}")
    await strad.init()
    GLOBAL_STATE.strad = strad


async def main():
    global strad
    global ws

    GLOBAL_STATE.register_lock('modal_lock')

    document.addEventListener(StradEvent.CANVAS_READY, create_proxy(register_listeners))
    document.addEventListener(StradEvent.CANVAS_READY, create_proxy(populate_dialog))
    document.addEventListener(StradEvent.PLAYER_ADDED, create_proxy(populate_dialog))

    loadmsg = document.getElementById(DE2.MODAL_LOAD_MSG.literal)
    jsc(f"setting up straD2")
    ws = await WsWrapper.create(broker=Strad.messagebroker, initializer=initialize_day, modal=loadmsg)


if __name__ == '__main__':
    loop = asyncio.get_running_loop()
    loop.run_until_complete(main())
    loop.run_until_complete(clock())
