export default class GameList extends HTMLElement
{
    static JOIN_CLICK_EVT = 'join-click';
    
    constructor()
    {
        super();

        this._shadowRoot = this.attachShadow({ mode: 'closed' });
    
        this._shadowRoot.innerHTML = `
            <link href="./assets/css/bootstrap.min.css" rel="stylesheet" />
            <link href="./assets/icons/css/fontawesome.min.css" rel="stylesheet" />
            <link href="./assets/icons/css/solid.min.css" rel="stylesheet" />

            <ul class="list-group list-group-flush">
                <template>
                    <li class="list-group-item px-0" data-room-id="">
                        <div class="hstack gap-2">
                            <div class="flex-grow-1 d-flex flex-column">
                                <strong class="room-name">Room name</strong>
                                <small>Player slots: <span class="player-slots">0</span></small>
                                <small>Spectator slots: <span class="spectator-slots">0</span></small>
                            </div>
                            <button type="button" class="btn btn-primary btn-sm game-button"><i class="fa-solid fa-gamepad"></i></button>
                            <button type="button" class="btn btn-outline-secondary btn-sm game-button"><i class="fa-solid fa-eye"></i></button>
                        </div>
                    </li>
                </template>
            </ul>
        `;

        this.list = this._shadowRoot.querySelector('ul');

        // Bind event listeners
        this.onBoundPlayButtonClick = this.onPlayButtonClick.bind(this);
        this.onBoundWatchButtonClick = this.onWatchButtonClick.bind(this);
    }

    connectedCallback()
    {
        // Nothing to do
    }

    reset()
    {
        for (let item of this.list.querySelectorAll('li[data-room-id'))
            this.removeListItem(item.dataset.roomId);
    }

    populateList(rooms)
    {
        for (let room of rooms)
            this.addListItem(room);
    }

    addListItem(room)
    {
        // Show only game rooms
        // Also password protected Rooms are skipped, to make this example simpler
        // (protection would require an interface element to input the password)
        if (!room.isGame || room.isHidden || room.isPasswordProtected)
            return;

        // Create game list item from template
        const template = this.list.querySelector('template');
        let node = template.content.cloneNode(true);
        node.firstElementChild.dataset.roomId = room.id;

        // Add game list item to container
        this.list.append(node);

        // When a node is cloned from a template, the cloned content is initially a DocumentFragment
        // When we append this fragment to the DOM, it gets consumed, meaning the original fragment is emptied after appending
        // So we need to re-select the element after appending
        let item = this.getListItem(room.id);

        // Set room name
        item.querySelector('.room-name').innerText = room.name;

        // Update game list item
        this.setItemState(room);
        
        // Add listeners to play and watch buttons
        const buttons = item.querySelectorAll('.game-button');
        buttons[0].addEventListener('click', this.onBoundPlayButtonClick);
        buttons[1].addEventListener('click', this.onBoundWatchButtonClick);
    }

    getListItem(roomId)
    {
        return this.list.querySelector(`li[data-room-id="${roomId}"`);
    }

    setItemState(room)
    {
        const item = this.getListItem(room.id);

        if (item != null)
        {
            const playerSlots = room.maxUsers - room.userCount;
            const spectatorSlots = room.maxSpectators - room.spectatorCount;

            // Set player count and spectator count in game list item
            item.querySelector('.player-slots').innerText = playerSlots;
            item.querySelector('.spectator-slots').innerText = spectatorSlots;

            // Enable/disable game play button
            item.querySelectorAll('.game-button')[0].disabled = playerSlots == 0;

            // Enable/disable game watch button
            item.querySelectorAll('.game-button')[1].disabled = spectatorSlots == 0;
        }
    }

    removeListItem(roomId)
    {
        const item = this.getListItem(roomId);

        if (item != null)
        {
            // Remove listeners to play and watch buttons
            const buttons = item.querySelectorAll('.game-button');
            buttons[0].removeEventListener('click', this.onBoundPlayButtonClick);
            buttons[1].removeEventListener('click', this.onBoundWatchButtonClick);

            // Remove game list item
            this.list.removeChild(item);
        }
    }

    getItemData(element)
    {
        return element.closest('li').dataset.roomId;
    }

    onPlayButtonClick(e)
    {
        this.fireJoinEvent(Number(this.getItemData(e.currentTarget)), false);
    }

    onWatchButtonClick(e)
    {
        this.fireJoinEvent(Number(this.getItemData(e.currentTarget)), true);
    }

    fireJoinEvent(roomId, asSpectator)
    {
        this.dispatchEvent(
            new CustomEvent(GameList.JOIN_CLICK_EVT, {
                detail: {
                    roomId: roomId,
                    asSpectator: asSpectator
                }
            })
        );
    }
}

customElements.define('game-list', GameList);