/*eslint prefer-const: "error"*/

let currentId = 0;
function addUniquePlaylistItemId(item) {
    if (!item.PlaylistItemId) {
        item.PlaylistItemId = 'playlistItem' + currentId;
        currentId++;
    }
}

function findPlaylistIndex(playlistItemId, list) {
    for (let i = 0, length = list.length; i < length; i++) {
        if (list[i].PlaylistItemId === playlistItemId) {
            return i;
        }
    }

    return -1;
}

class PlayQueueManager {
    constructor() {
        this._sortedPlaylist = [];
        this._playlist = [];
        this._repeatMode = 'RepeatNone';
        this._shuffleMode = 'Sorted';
    }

    getPlaylist() {
        return this._playlist.slice(0);
    }

    setPlaylist(items) {
        items = items.slice(0);

        for (let i = 0, length = items.length; i < length; i++) {
            addUniquePlaylistItemId(items[i]);
        }

        this._currentPlaylistItemId = null;
        this._playlist = items;
        this._repeatMode = 'RepeatNone';
    }

    queue(items) {
        for (let i = 0, length = items.length; i < length; i++) {
            addUniquePlaylistItemId(items[i]);

            this._playlist.push(items[i]);
        }
    }

    shufflePlaylist() {
        this._sortedPlaylist = [];
        for (const item of this._playlist) {
            this._sortedPlaylist.push(item);
        }
        const currentPlaylistItem = this._playlist.splice(this.getCurrentPlaylistIndex(), 1)[0];

        for (let i = this._playlist.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * i);
            const temp = this._playlist[i];
            this._playlist[i] = this._playlist[j];
            this._playlist[j] = temp;
        }
        this._playlist.unshift(currentPlaylistItem);
        this._shuffleMode = 'Shuffle';
    }

    sortShuffledPlaylist() {
        this._playlist = [];
        for (const item of this._sortedPlaylist) {
            this._playlist.push(item);
        }
        this._sortedPlaylist = [];
        this._shuffleMode = 'Sorted';
    }

    clearPlaylist(clearCurrentItem = false) {
        const currentPlaylistItem = this._playlist.splice(this.getCurrentPlaylistIndex(), 1)[0];
        this._playlist = [];
        if (!clearCurrentItem) {
            this._playlist.push(currentPlaylistItem);
        }
    }

    queueNext(items) {
        for (let i = 0, length = items.length; i < length; i++) {
            addUniquePlaylistItemId(items[i]);
        }

        let currentIndex = this.getCurrentPlaylistIndex();

        if (currentIndex === -1) {
            currentIndex = this._playlist.length;
        } else {
            currentIndex++;
        }

        arrayInsertAt(this._playlist, currentIndex, items);
    }

    getCurrentPlaylistIndex() {
        return findPlaylistIndex(this.getCurrentPlaylistItemId(), this._playlist);
    }

    getCurrentItem() {
        const index = findPlaylistIndex(this.getCurrentPlaylistItemId(), this._playlist);

        return index === -1 ? null : this._playlist[index];
    }

    getCurrentPlaylistItemId() {
        return this._currentPlaylistItemId;
    }

    setPlaylistState(playlistItemId) {
        this._currentPlaylistItemId = playlistItemId;
    }

    setPlaylistIndex(playlistIndex) {
        if (playlistIndex < 0) {
            this.setPlaylistState(null);
        } else {
            this.setPlaylistState(this._playlist[playlistIndex].PlaylistItemId);
        }
    }

    removeFromPlaylist(playlistItemIds) {
        if (this._playlist.length <= playlistItemIds.length) {
            return {
                result: 'empty'
            };
        }

        const currentPlaylistItemId = this.getCurrentPlaylistItemId();
        const isCurrentIndex = playlistItemIds.indexOf(currentPlaylistItemId) !== -1;

        this._sortedPlaylist = this._sortedPlaylist.filter(function (item) {
            return !playlistItemIds.includes(item.PlaylistItemId);
        });

        this._playlist = this._playlist.filter(function (item) {
            return !playlistItemIds.includes(item.PlaylistItemId);
        });

        return {
            result: 'removed',
            isCurrentIndex: isCurrentIndex
        };
    }

    movePlaylistItem(playlistItemId, newIndex) {
        const playlist = this.getPlaylist();

        let oldIndex;
        for (let i = 0, length = playlist.length; i < length; i++) {
            if (playlist[i].PlaylistItemId === playlistItemId) {
                oldIndex = i;
                break;
            }
        }

        if (oldIndex === -1 || oldIndex === newIndex) {
            return {
                result: 'noop'
            };
        }

        if (newIndex >= playlist.length) {
            throw new Error('newIndex out of bounds');
        }

        moveInArray(playlist, oldIndex, newIndex);

        this._playlist = playlist;

        return {
            result: 'moved',
            playlistItemId: playlistItemId,
            newIndex: newIndex
        };
    }

    reset() {
        this._sortedPlaylist = [];
        this._playlist = [];
        this._currentPlaylistItemId = null;
        this._repeatMode = 'RepeatNone';
        this._shuffleMode = 'Sorted';
    }

    setRepeatMode(value) {
        const repeatModes = ['RepeatOne', 'RepeatAll', 'RepeatNone'];
        if (repeatModes.includes(value)) {
            this._repeatMode = value;
        } else {
            throw new TypeError('invalid value provided for setRepeatMode');
        }
    }

    getRepeatMode() {
        return this._repeatMode;
    }

    setShuffleMode(value) {
        switch (value) {
            case 'Shuffle':
                this.shufflePlaylist();
                break;
            case 'Sorted':
                this.sortShuffledPlaylist();
                break;
            default:
                throw new TypeError('invalid value provided to setShuffleMode');
        }
    }

    toggleShuffleMode() {
        switch (this._shuffleMode) {
            case 'Shuffle':
                this.setShuffleMode('Sorted');
                break;
            case 'Sorted':
                this.setShuffleMode('Shuffle');
                break;
            default:
                throw new TypeError('current value for shufflequeue is invalid');
        }
    }

    getShuffleMode() {
        return this._shuffleMode;
    }

    getNextItemInfo() {
        let newIndex;
        const playlist = this.getPlaylist();
        const playlistLength = playlist.length;

        switch (this.getRepeatMode()) {
            case 'RepeatOne':
                newIndex = this.getCurrentPlaylistIndex();
                break;
            case 'RepeatAll':
                newIndex = this.getCurrentPlaylistIndex() + 1;
                if (newIndex >= playlistLength) {
                    newIndex = 0;
                }
                break;
            default:
                newIndex = this.getCurrentPlaylistIndex() + 1;
                break;
        }

        if (newIndex < 0 || newIndex >= playlistLength) {
            return null;
        }

        const item = playlist[newIndex];

        if (!item) {
            return null;
        }

        return {
            item: item,
            index: newIndex
        };
    }
}

function arrayInsertAt(destArray, pos, arrayToInsert) {
    let args = [];
    args.push(pos); // where to insert
    args.push(0); // nothing to remove
    args = args.concat(arrayToInsert); // add on array to insert
    destArray.splice.apply(destArray, args); // splice it in
}

function moveInArray(array, from, to) {
    array.splice(to, 0, array.splice(from, 1)[0]);
}

export default PlayQueueManager;
