#include utils.js
#include watcher.js

const MszAudioEmbedPlayerEvents = function() {
    return [
        'play', 'pause', 'stop',
        'mute', 'volume',
        'rate', 'duration', 'time',
    ];
};

const MszAudioEmbed = function(player) {
    const elem = $e({
        attrs: {
            classList: ['aembed', 'aembed-' + player.getType()],
        },
        child: player,
    });

    return {
        getElement: function() {
            return elem;
        },
        appendTo: function(target) {
            target.appendChild(elem);
        },
        insertBefore: function(ref) {
            $ib(ref, elem);
        },
        nuke: function() {
            $r(elem);
        },
        replaceElement(target) {
            $ib(target, elem);
            $r(target);
        },
        getPlayer: function() {
            return player;
        },
    };
};

const MszAudioEmbedPlayer = function(metadata, options) {
    options = options || {};

    const shouldAutoplay = options.autoplay === undefined || options.autoplay,
        haveNativeControls = options.nativeControls !== undefined && options.nativeControls;

    const playerAttrs = {
        src: metadata.url,
        style: {},
    };

    if(shouldAutoplay)
        playerAttrs.autoplay = 'autoplay';
    if(haveNativeControls)
        playerAttrs.controls = 'controls';

    const watchers = new MszWatcherCollection;
    watchers.define(MszAudioEmbedPlayerEvents());

    const player = $e({
        tag: 'audio',
        attrs: playerAttrs,
    });

    const pub = {
        getElement: function() {
            return player;
        },
        appendTo: function(target) {
            target.appendChild(player);
        },
        insertBefore: function(ref) {
            $ib(ref, player);
        },
        nuke: function() {
            $r(player);
        },
        replaceElement(target) {
            $ib(target, player);
            $r(target);
        },
        getType: function() { return 'external'; },
    };

    watchers.proxy(pub);

    player.addEventListener('play', function() { watchers.call('play', pub); });

    const pPlay = function() { player.play(); };
    pub.play = pPlay;

    const pPause = function() { player.pause(); };
    pub.pause = pPause;

    let stopCalled = false;
    player.addEventListener('pause', function() {
        watchers.call(stopCalled ? 'stop' : 'pause', pub);
        stopCalled = false;
    });

    const pStop = function() {
        stopCalled = true;
        player.pause();
        player.currentTime = 0;
    };
    pub.stop = pStop;

    const pIsPlaying = function() { return !player.paused; };
    pub.isPlaying = pIsPlaying;

    const pIsMuted = function() { return player.muted; };
    pub.isMuted = pIsMuted;

    let lastMuteState = player.muted;
    player.addEventListener('volumechange', function() {
        if(lastMuteState !== player.muted) {
            lastMuteState = player.muted;
            watchers.call('mute', pub, [lastMuteState]);
        } else
            watchers.call('volume', pub, [player.volume]);
    });

    const pSetMuted = function(state) { player.muted = state; };
    pub.setMuted = pSetMuted;

    const pGetVolume = function() { return player.volume; };
    pub.getVolume = pGetVolume;

    const pSetVolume = function(volume) { player.volume = volume; };
    pub.setVolume = pSetVolume;

    const pGetPlaybackRate = function() { return player.playbackRate; };
    pub.getPlaybackRate = pGetPlaybackRate;

    player.addEventListener('ratechange', function() {
        watchers.call('rate', pub, [player.playbackRate]);
    });

    const pSetPlaybackRate = function(rate) { player.playbackRate = rate; };
    pub.setPlaybackRate = pSetPlaybackRate;

    window.addEventListener('durationchange', function() {
        watchers.call('duration', pub, [player.duration]);
    });

    const pGetDuration = function() { return player.duration; };
    pub.getDuration = pGetDuration;

    window.addEventListener('timeupdate', function() {
        watchers.call('time', pub, [player.currentTime]);
    });

    const pGetTime = function() { return player.currentTime; };
    pub.getTime = pGetTime;

    const pSeek = function(time) { player.currentTime = time; };
    pub.seek = pSeek;

    return pub;
};

const MszAudioEmbedPlaceholder = function(metadata, options) {
    options = options || {};

    if(typeof options.player !== 'function' && typeof options.onclick !== 'function')
        throw 'Neither a player nor an onclick handler were provided.';

    let title = [],
        album = undefined;
    if(metadata.media !== undefined && metadata.media.tags !== undefined) {
        const tags = metadata.media.tags;

        if(tags.title !== undefined) {
            if(tags.artist !== undefined) {
                title.push({
                    tag: 'span',
                    attrs: {
                        className: 'aembedph-info-title-artist',
                    },
                    child: tags.artist,
                });
                title.push(' - ');
            }

            title.push({
                tag: 'span',
                attrs: {
                    className: 'aembedph-info-title-title',
                },
                child: tags.title,
            });
        } else {
            title.push({
                tag: 'span',
                attrs: {
                    className: 'aembedph-info-title-title',
                },
                child: metadata.title,
            });
        }

        if(tags.album !== undefined && tags.album !== tags.title)
            album = tags.album;
    }

    const infoChildren = [];

    infoChildren.push({
        tag: 'h1',
        attrs: {
            className: 'aembedph-info-title',
        },
        child: title,
    });

    infoChildren.push({
        tags: 'p',
        attrs: {
            className: 'aembedph-info-album',
        },
        child: album,
    });

    infoChildren.push({
        tag: 'div',
        attrs: {
            className: 'aembedph-info-site',
        },
        child: metadata.site_name,
    });

    const style = [];
    if(typeof metadata.color !== 'undefined')
        style.push('--aembedph-colour: ' + metadata.color);

    const coverBackground = $e({
        attrs: {
            className: 'aembedph-bg',
        },
        child: {
            tag: 'img',
            attrs: {
                alt: '',
                src: metadata.image,
                onerror: function(ev) {
                    coverBackground.classList.add('aembedph-bg-none');
                },
            },
        },
    });

    const coverPreview = $e({
        attrs: {
            className: 'aembedph-info-cover',
        },
        child: {
            tag: 'img',
            attrs: {
                alt: '',
                src: metadata.image,
                onerror: function(ev) {
                    coverPreview.classList.add('aembedph-info-cover-none');
                },
            },
        },
    });

    const pub = {};

    const elem = $e({
        attrs: {
            className: ('aembedph aembedph-' + (options.type || 'external')),
            style: style.join(';'),
            title: metadata.title,
        },
        child: [
            coverBackground,
            {
                attrs: {
                    className: 'aembedph-fg',
                },
                child: [
                    {
                        attrs: {
                            className: 'aembedph-info',
                        },
                        child: [
                            coverPreview,
                            {
                                attrs: {
                                    className: 'aembedph-info-body',
                                },
                                child: infoChildren,
                            }
                        ],
                    },
                    {
                        attrs: {
                            className: 'aembedph-play',
                            onclick: function(ev) {
                                if(ev.target.tagName.toLowerCase() === 'a')
                                    return;

                                if(typeof options.onclick === 'function') {
                                    options.onclick(ev);
                                    return;
                                }

                                const player = new options.player(metadata, options);

                                const embed = new MszAudioEmbed(player);
                                if(options.autoembed === undefined || options.autoembed)
                                    embed.replaceElement(elem);

                                if(typeof options.onembed === 'function')
                                    options.onembed(embed);
                            },
                        },
                        child: [
                            {
                                attrs: {
                                    className: 'aembedph-play-internal',
                                },
                                child: {
                                    tag: 'i',
                                    attrs: {
                                        className: 'fas fa-play fa-3x fa-fw',
                                    },
                                },
                            },
                            {
                                attrs: {
                                    className: 'aembedph-play-external',
                                },
                                child: {
                                    tag: 'a',
                                    attrs: {
                                        className: 'aembedph-play-external-link',
                                        href: metadata.url,
                                        target: '_blank',
                                        rel: 'noopener',
                                    },
                                    child: ('or listen on ' + metadata.site_name + '?')
                                },
                            }
                        ],
                    }
                ],
            },
        ],
    });

    pub.getElement = function() { return elem; };
    pub.appendTo = function(target) { target.appendChild(elem); };
    pub.insertBefore = function(ref) { $ib(ref, elem); };
    pub.nuke = function() {
        $r(elem);
    };
    pub.replaceElement = function(target) {
        $ib(target, elem);
        $r(target);
    };

    return pub;
}
