const moment = require('moment');
//const clsLogger = require('../logs/clsLogger').clsLogger;
const PlaylistManager = require('./PlaylistManager');
let pl = null;
const LogDB = require('../db/logDB');
require('linqjs');
const _ = require('lodash');
//const chalk = require('chalk');
const ini = require('ini');
const fs = require('fs');

const djPlayer = class djPlayer {
    constructor({ db, moment, config, utils, schedulesdb, decodeOnly = true, logger } = {}) {
        this.db = db;
        this.moment = moment;
        this.config = config;
        this.utils = utils;
        this.logger = logger;
        this.schedulesdb = schedulesdb;
        this.djEnabled = this.config.DJ.djEnabled;
        this.decodeOnly = decodeOnly;
        this.logDB = new LogDB();
        this.activePlayList = null;
        this.currentList = '';
        this.isLooping = this.config.DJ.DJLoop;
        this.autoStart = this.config.DJ.DJAutoStart;
        this.enableShuffle = false;
        this.activeFile = null;
        this.channel = 0;
        this.isPlaying = false;
        this.scheduleID = this.config.DJ.DJScheduleID;
        this.enableAnnounces = false;
        pl = new PlaylistManager({ moment, utils, config, isLooping: this.config.DJ.DJLoop, autoStart: this.config.DJ.DJAutoStart, fadeInEnabled: true, musicVolume: 100, decodeOnly: this.decodeOnly, logger });
        this.pl = pl;
        if(this.autoStart == 1) {
            this.Play(this.scheduleID, true, this.isLooping, this.enableShuffle);
        }
        this.eventTypes = {
            playlistFinished: 'playlistFinished',
            stateChanged: 'stateChanged',
            fileChanged: 'fileChanged',
            positionChange: 'positionChange',
            vumeter: 'vumeter',
            djPlayerStarted: 'djPlayerStarted',
            djPlayerStopped: 'djPlayerStopped'
        };
        this.nowPlaying = {
            FileName: '',
            OriginalName: '',
            TotalFiles: 0,
            TotalDownloaded: 0,
            Position: 0,
            Duration: 0,
            vumeterLeft: 0,
            vumeterRight: 0,
            FilePosition: 0
        };
        pl.on(pl.playerEvents.fileChanged, async (chan, FileName, activeFile, duration, index) => {
            this.nowPlaying.TotalFiles = this.pl.files.length;
            this.nowPlaying.TotalDownloaded = this.pl.totalDownloaded;
            this.nowPlaying.FilePosition = index + 1;
            this.nowPlaying.FileName = activeFile.FileName;
            this.nowPlaying.OriginalName = activeFile.OriginalName;
            this.emit(this.eventTypes.fileChanged, chan, FileName, activeFile, duration, index);
            this.activeFile = pl.activeFile;
            this.logger.PlayingDj(`${activeFile.FileName} - ${activeFile.OriginalName} - ${this.moment({
                hour: 0, minute: 0, second: 0
            }).second(duration).format('mm:ss')}`);
            // let obj = {
            //   FileID: activeFile.FileID,
            //   FileName: activeFile.FileName,
            //   OriginalName: activeFile.OriginalName,
            //   PlayDate: new moment().utc(true).toJSON().substr(0, 19),
            //   MusicType: 2,
            //   Duration: duration,
            // };
            // await this.logDB.insertLog(obj);
            //   this.logger.PlayerEventsDJ(chalk.blue(`${activeFile.FileName} - ${activeFile.OriginalName} - ${this.moment({
            //       hour: 0, minute: 0, second: 0}).second(duration).format('mm:ss')
            //       }`));
        });
        pl.on(pl.playerEvents.playlistFinished, () => {
            this.emit(this.eventTypes.playlistFinished, this.activePlayList);
        });
        pl.on(pl.playerEvents.positionChange, (activeFile, pos, dur, position, duration) => {
            this.nowPlaying.Duration = duration;
            this.nowPlaying.Position = position;
            this.emit(this.eventTypes.positionChange, activeFile, pos, dur, position, duration);
        });
        pl.on(pl.playerEvents.stateChanged, (state) => {
            this.emit(this.eventTypes.stateChanged, state);
        });
        pl.on(pl.playerEvents.vumeter, (left, right) => {
            if(this.isPlaying){
                this.nowPlaying.vumeterLeft = left;
                this.nowPlaying.vumeterRight = right;
                this.emit(this.eventTypes.vumeter, left, right);
            }
        });

        this._initSystem()

    }

    async _initSystem() {

        /*
        add event listeners
         */
        this.pl.isTimeManagementEnabled = false;
        this.logger.PlayerEventsDJ('Dj Player started');
    }

    get mixer() {
        return pl.mixer;
    }

    async initdb() {
        await this.db.initsync();
    }

    async Play(scheduleID, canAnnouncePlay, isLooping, shuffle) {
        this.scheduleID = scheduleID;
        this.isLooping = isLooping;
        this.config.DJ.DJScheduleID = this.scheduleID;
        this.config.DJ.DJLoop = this.isLooping;
        try {
            fs.writeFileSync(this.utils._filepath, ini.stringify(this.config, { section: '' }));
        } catch (e) {
            this.logger.PlayerEventsDJ(`Error writing schedule: ${this.scheduleID} and looping: ${this.isLooping} to config.ini, err: ${e}`);
        }
        this.enableAnnounces = canAnnouncePlay;
        this.pl.isLooping = isLooping;
        this.enableShuffle = shuffle;
        let schedules = await this.schedulesdb.getSchedules();
        if (!schedules || schedules.length == 0) {
            setTimeout(() => {
                this.Play(this.scheduleID, this.enableAnnounces, this.pl.isLooping, this.enableShuffle);
            }, 500);
            this.isPlaying = false;
            return;
        }
        let scheduleToPlay = schedules.where(c => c.scheduleID == this.scheduleID);
        if (!scheduleToPlay || scheduleToPlay.length == 0) {
            this.logger.PlayerEventsDJ(`selected schedule is not present in db, schedule ID: ${this.scheduleID}`);
            setTimeout(() => {
                this.Play(this.scheduleID, this.enableAnnounces, this.pl.isLooping, this.enableShuffle);
            }, 500);
            this.isPlaying = false;
            return;
        }
        let filesToPlay = scheduleToPlay[0].Schedules_Details;
        if (!filesToPlay || filesToPlay.length == 0) {
            this.logger.PlayerEventsDJ(`there are no schedule details available for selected playlist: ${this.scheduleID}`);
            this.isPlaying = false;
            return;
        }
        let lastPlayed = null;
        this.activePlayList = scheduleToPlay;
        this.currentList = scheduleToPlay[0].scheduleName;
        this.isPlaying = true;
        this.emit(this.eventTypes.djPlayerStarted);
        if (this.enableShuffle) {
            let shuffled = _.shuffle(filesToPlay);
            pl.addFiles(shuffled, lastPlayed);
        } else {
            pl.addFiles(filesToPlay, lastPlayed);
        }
        this.logger.PlayerEventsDJ(`added scheduleID: ${this.scheduleID} - ${filesToPlay.length} songs to playlist manager`);
    }

    playNext() {
        this.logger.PlayerEventsDJ('playing next song');
        if (this.pl.activeChannel &&  this.pl.activeChannel != 0) {
            this.pl.activeScheduleChannels.remove(this.pl.activeChannel);
            this.pl.player.StopChannel(this.pl.activeChannel);
            this.pl.Play();
        }
    }

    Stop() {
        this.isPlaying = false;
        this.emit(this.eventTypes.djPlayerStopped);
        this.logger.PlayerEventsDJ('stopping play');
        if (this.pl.activeChannel != 0) {
            this.nowPlaying.TotalFiles = 0;
            this.nowPlaying.Duration = 0;
            this.nowPlaying.Position = 0;
            this.nowPlaying.FileName = '';
            this.nowPlaying.FilePosition = 0;
            this.nowPlaying.OriginalName = '';
            this.pl.clearFiles();
            if(this.pl.activeChannel != 0) {
                this.pl.activeScheduleChannels.remove(this.pl.activeChannel);
                this.pl.player.StopChannel(this.pl.activeChannel);
            }
        }
    }

    Shuffle() {
        this.logger.PlayerEventsDJ('Clearing playlist manager files, shuffling active list and readding to playlist manager files');
        this.pl.clearFiles();
        //this.enableShuffle = true;
        if (this.enableShuffle && this.isPlaying) {
            this.logger.PlayerEventsDJ('Shuffle is enabled while already playing, clearing list and adding shuffled list.');
            let shuffled = _.shuffle(this.activePlayList[0].Schedules_Details);
            //add files method requires last song played, therefor we pass null
            this.pl.addFiles(shuffled, null);
        } else {
            if (this.isPlaying) {
                this.logger.PlayerEventsDJ('Shuffle is disabled while already playing, clearing list and adding unshuffled list');
                this.pl.addFiles(this.activePlayList[0].Schedules_Details);
            }
        }
    }

    Loop() {
        this.logger.PlayerEventsDJ(`Setting loop ${this.isLooping}`);
        this.pl.isLooping = this.isLooping;
    }

    async getCurrentPlaylist() {
        let schedules = await this.schedulesdb.getSchedules();
        let downloaded = schedules.select(c => {
            return {
                scheduleID: c.scheduleID,
                scheduleName: c.scheduleName,
                total: c.Schedules_Details.where(d => d.isDownloaded == 1).length
            }
        }).orderBy(d => d.scheduleName);
        schedules = null;
        return downloaded;
    }
};


const util = require('util');
const EventEmitter = require('events').EventEmitter;
util.inherits(djPlayer, EventEmitter);
module.exports = djPlayer;
