import * as bootstrap from 'bootstrap';
import './audio-meter.js';

export default class CallPanel extends HTMLElement
{
    static END_CALL_EVT = 'end-call';
    static TOGGLE_MUTE_EVT = 'toggle-mute';

    static observedAttributes = ['disabled','muted'];

    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" />

            <style>
                .list-group-item {
                    background-color: unset;
                }
                
                .hidden {
                    display: none;
                }
            </style>

            <div class="d-none d-md-block">
                <div class="hstack gap-2 align-items-baseline">
                    <h2 class="display-6 m-0">Call</h2>
                </div>
                <hr>
            </div>
            <div>
                <div class="hstack gap-3 justify-content-evenly">
                    <button id="endCallButton" type="button" class="btn btn-danger"><i class="fa-solid fa-phone-slash"></i></button>
                    <button id="muteButton" type="button" class="btn btn-outline-secondary" data-bs-toggle="button"><i class="fa-solid fa-microphone-alt-slash"></i></button>
                </div>
                <audio-meter id="myAudioMeter" class="hidden"></audio-meter>
            </div>
            <hr>
            <div class="flex-grow-1 overflow-y-auto" style="height: 0;">
                <ul class="list-group list-group-flush">
                <template>
                    <li class="list-group-item px-0" data-user-name="">
                        <div class="vstack align-items-baseline">
                            <div class="hstack gap-2 justify-content-between">
                                <strong class="user-name"></strong>
                                <small class="status text-body-tertiary"></small>
                            </div>
                            <audio-meter class="audio-meter hidden"></audio-meter>
                        </div>
                    </li>
                </template>
                </ul>
            </div>
        `;

        this.endCallButton = this._shadowRoot.querySelector('#endCallButton');
        this.muteButton = this._shadowRoot.querySelector('#muteButton');
        this.list = this._shadowRoot.querySelector('ul');
        this.myAudioMeter = this._shadowRoot.querySelector('#myAudioMeter');
        this.myAudioMeter.hideDelay();

        // Bind event listeners
        this.boundOnEndCallClick = this.onEndCallClick.bind(this);
        this.boundOnMuteClick = this.onMuteClick.bind(this);

        // Init Bootstrap button to enable toggle behavior
        this.bsMuteButton = bootstrap.Button.getOrCreateInstance(this.muteButton);
    }

    connectedCallback()
    {
        // Add listeners
        this.endCallButton.addEventListener('click', this.boundOnEndCallClick);
        this.muteButton.addEventListener('click', this.boundOnMuteClick);
    }

    attributeChangedCallback(name, oldValue, newValue)
    {
        switch (name)
        {
            case 'disabled':
                this.disableInput(newValue === 'true');
                break;
            case 'muted':
                this.toggleMuteButton();
                break;
        }
    }

    get muted()
    {
        return this.hasAttribute('muted');
    }

    set muted(value)
    {
        if (value)
            this.setAttribute('muted', '');
        else
            this.removeAttribute('muted');
    }

    reset()
    {
        this.list.querySelectorAll(':not(template)').forEach(child => child.remove());

        // Enable input by removing the "disabled" attribute
        this.removeAttribute('disabled');

        this.muted = false;
    }

    disableInput(disable)
    {
        this.endCallButton.disabled = disable;
        this.muteButton.disabled = disable;

        if (disable)
            this.myAudioMeter.classList.add('hidden');
    }

    toggleMuteButton()
    {
        // Toggle mute button
        this.bsMuteButton.toggle();
    }

    showMyAudioMeter(asi)
    {
        this.myAudioMeter.classList.remove('hidden');
        this.myAudioMeter.streamInfo = asi;
    }

    hasParticipant(userName)
    {
        return this.getListItem(userName) != null;
    }

    addParticipant(userName)
    {
        // Create call list item from template
        const template = this.list.querySelector('template');
        let node = template.content.cloneNode(true);
        node.firstElementChild.dataset.userName = userName;

        // Add 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
        const item = this.getListItem(userName);
        item.querySelector('.user-name').innerText = userName;
        item.querySelector('.status').innerText = "Connecting...";
    }

    async removeParticipant(userName, reason)
    {
        const item = this.getListItem(userName);

        if (item != null)
        {
            item.querySelector('.status').innerText = reason;
            item.querySelector('.audio-meter').classList.add('hidden');

            // Wait 2 seconds then remove
            await new Promise(resolve => setTimeout(resolve, 2000));

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

    updateParticipant(asi)
    {
        const item = this.getListItem(asi.user.name);

		if (item != null)
		{
            item.querySelector('.status').innerText = "";

            const audioMeter = item.querySelector('.audio-meter');
            audioMeter.classList.remove('hidden');
            audioMeter.streamInfo = asi;
		}
    }

    getListItem(userName)
    {
        return this.list.querySelector(`li[data-user-name="${userName}"`);
    }

    onEndCallClick(e)
    {
        // Fire custom event
        this.dispatchEvent(
            new CustomEvent(CallPanel.END_CALL_EVT)
        );
    }

    onMuteClick(e)
    {
        this.muted = !this.muted;

        // Fire custom event
        this.dispatchEvent(
            new CustomEvent(CallPanel.TOGGLE_MUTE_EVT)
        );
    }
}

customElements.define('call-panel', CallPanel);