<template>
    <div class="a-player">
        <div :class="['a-player-panels', panel ? 'is-open' : '']">
            <template v-for="(info, key) in playlists" v-bind:key="key">
                <APlaylist
                        :ref="key" class="a-player-panel a-playlist"
                        v-show="panel == key && sets[key].length"
                        :actions="['page', key != 'pin' && 'pin' || '']"
                        :editable="true" :player="self" :set="sets[key]"
                        @select="togglePlay(key, $event.index)"
                        listClass="menu-list" itemClass="menu-item">
                    <template v-slot:header="">
                        <div class="title is-flex-grow-1">
                            <span class="icon">
                                <i :class="info[1]"></i>
                            </span>
                            {{ info[0] }}
                        </div>
                        <button class="action button no-border">
                            <span class="icon" @click.stop="togglePanel()">
                                <i class="fa fa-close"></i>
                            </span>
                        </button>
                    </template>
                </APlaylist>
            </template>
        </div>

        <div class="a-player-progress" v-if="loaded && duration">
            <AProgress v-if="loaded && duration" :value="currentTime" :max="this.duration"
                :format="displayTime"
                @select="audio.currentTime = $event"></AProgress>
        </div>
        <div class="a-player-bar button-group">
            <button class="button" @click="togglePlay()"
                    :title="buttonTitle" :aria-label="buttonTitle">
                <span class="fas fa-pause" v-if="playing"></span>
                <span class="fas fa-play" v-else></span>
            </button>
            <div :class="['a-player-bar-content', loaded && duration ? 'has-progress' : '']">
                <slot name="content" :loaded="loaded" :live="live" :current="current"></slot>
            </div>
            <button class="button has-text-weight-bold" v-if="loaded" @click="play()"
                    title="Live">
                <span class="icon is-size-6 has-text-danger">
                    <span class="fa fa-circle"></span>
                </span>
            </button>
            <template v-if="sets">
                <template v-for="(info, key) in playlists" v-bind:key="key">
                    <button :class="playlistButtonClass(key)"
                            @click="togglePanel(key)"
                            v-show="sets[key] && sets[key].length">
                        <span class="is-size-6">{{ sets[key] && sets[key].length }}</span>
                        <span class="icon">
                            <i :class="info[1]"></i>
                        </span>
                    </button>
                </template>
            </template>
        </div>
    </div>
</template>

<script>
import {reactive} from 'vue'
import Live from '../live'
import Sound from '../sound'
import {Set} from '../model'
import APlaylist from './APlaylist'
import AProgress from './AProgress'


export const State = {
    paused: 0,
    playing: 1,
    loading: 2,
}

export default {
    components: { APlaylist, AProgress },

    data() {
        let audio = new Audio();
        audio.addEventListener('ended', e => this.onState(e));
        audio.addEventListener('pause', e => this.onState(e));
        audio.addEventListener('playing', e => this.onState(e));
        audio.addEventListener('timeupdate', () => {
            this.currentTime = this.audio.currentTime;
        });
        audio.addEventListener('durationchange', () => {
            this.duration = Number.isFinite(this.audio.duration) ? this.audio.duration : null;
        });

        let live = this.liveArgs ? reactive(new Live(this.liveArgs)) : null;
        live && live.refresh();

        const sets = {}
        for(const key in this.playlists)
            sets[key] = Set.storeLoad(Sound, 'playlist.' + key,
                {max: 30, unique: true})

        return {
            audio, duration: 0, currentTime: 0, state: State.paused,
            live,

            /// Loaded item
            loaded: null,
            //! Active panel name
            panel: null,
            //! current playing playlist name
            playlistName: null,
            //! players' playlists' sets
            sets,
        }
    },

    props: {
        buttonTitle: String,
        liveArgs: Object,
        ///! dict of {'slug': ['Label', 'icon']}
        playlists: Object,
    },

    computed: {
        self() { return this; },
        paused() { return this.state == State.paused; },
        playing() { return this.state == State.playing; },
        loading() { return this.state == State.loading; },

        playlist() {
            return this.playlistName ? this.$refs[this.playlistName][0] : null;
        },

        current() {
            return this.loaded ? this.loaded : this.live && this.live.current;
        },
    },

    methods: {
        displayTime(seconds) {
            seconds = parseInt(seconds);
            let s = seconds % 60;
            seconds = (seconds - s) / 60;
            let m = seconds % 60;
            let h = (seconds - m) / 60;

            let [ss,mm,hh] = [s.toString().padStart(2, '0'),
                              m.toString().padStart(2, '0'),
                              h.toString().padStart(2, '0')];
            return h ? `${hh}:${mm}:${ss}` : `${mm}:${ss}`;
        },

        playlistButtonClass(name) {
            let set = this.sets[name];
            return (set ? (set.length ? "" : "has-text-grey-light ")
                       + (this.panel == name ? "open"
                          : this.playlistName == name ? 'active' : '') : '')
                + " button";
        },

        /// Show/hide panel
        togglePanel(panel) { this.panel = this.panel == panel ? null : panel },
        /// Return True if item is loaded
        isLoaded(item) { return this.loaded && this.loaded.id == item.id },
        /// Return True if item is loaded
        isPlaying(item) { return this.isLoaded(item) && !this.paused },

        _setPlaylist(playlist) {
            this.playlistName = playlist;
            for(var p in this.sets)
                if(p != playlist && this.$refs[p])
                    this.$refs[p][0].unselect();
        },

        /// Load a sound from playlist or live
        load(playlist=null, index=0) {
            let src = null;

            // from playlist
            if(playlist !== null && index != -1) {
                let item = this.$refs[playlist][0].get(index);
                if(!item)
                    throw `No sound at index ${index} for playlist ${playlist}`;
                this.loaded = item
                src = item.src;
            }
            // from live
            else {
                this.loaded = null;
                src = this.live.src;
            }

            this._setPlaylist(playlist);

            // load sources
            const audio = this.audio;
            if(src instanceof Array) {
                audio.innerHTML = '';
                audio.removeAttribute('src');
                for(var s of src) {
                    let source = document.createElement('source');
                    source.setAttribute('src', s);
                    audio.appendChild(source)
                }
            }
            else {
                audio.src = src;
            }
            audio.load();
        },

        play(playlist=null, index=0) {
            this.load(playlist, index);
            this.audio.play().catch(e => console.error(e))
        },

        /// Push items to playlist (by name)
        push(playlist, ...items) {
            return this.sets[playlist].push(...items);
        },

        /// Push and play items
        playItems(playlist, ...items) {
            let index = this.push(playlist, ...items);
            this.$refs[playlist][0].selectedIndex = index;
            this.play(playlist, index);
        },

        /// Handle click event that plays multiple items (from `data-sounds` attribute)
        playButtonClick(event) {
            var items = JSON.parse(event.currentTarget.dataset.sounds);
            this.playItems('queue', ...items);
        },

        /// Pause
        pause() {
            this.audio.pause()
        },

        //! Play/pause
        togglePlay(playlist=null, index=0) {
            if(playlist !== null) {
                this.panel = null;
                let item = this.sets[playlist].get(index);
                if(!this.playlist || this.playlistName !== playlist || this.loaded != item) {
                    this.play(playlist, index);
                    return;
                }
            }
            if(this.paused)
                this.audio.play().catch(e => console.error(e))
            else
                this.audio.pause();
        },

        //! Pin/Unpin an item
        togglePlaylist(playlist, item) {
            const set = this.sets[playlist]
            let index = set.findIndex(item);
            if(index > -1)
                set.remove(index);
            else {
                set.push(item);
                // this.$refs.pinPlaylistButton.focus();
            }
        },

        /// Audio player state change event
        onState(event) {
            const audio = this.audio;
            this.state = audio.paused ? State.paused : State.playing;

            if(event.type == 'ended' && (!this.playlist || this.playlist.selectNext() == -1))
                this.play();
        },

    },

    mounted() {
        this.load();
    },
}
</script>
