import * as React from 'react';
import * as ReactDOM from 'react-dom';
import videojs from 'video.js';
import { VideoPlayerInfo } from './VideoPlayerInfo';

export interface IVjsVideoPlayerInfoOptions extends videojs.ComponentOptions {
    title: string;
    displayTime: boolean;
}

const vjsComponent = videojs.getComponent('Component');
const vjsTimeDisplay = videojs.getComponent('TimeDisplay');

class VjsVideoPlayerInfo extends vjsTimeDisplay {

    public static ComponentName = 'vjsVideoPlayerInfo';

    private specificOptions: IVjsVideoPlayerInfoOptions;
    private currentTime: string;
    private cachedDuration: number;
    private currentDuration: string;

    constructor(player: videojs.Player, options: videojs.ComponentOptions) {
        super(player, options);
        this.specificOptions = options as IVjsVideoPlayerInfoOptions;

        this.mount = this.mount.bind(this);

        player.ready(() => {
            this.mount();
        });

        this.on(player, 'ended', () => { this.handleEnded(); });
        this.on(player, 'durationchange', () => { this.updateDuration(); });
        this.on(player, 'loadstart', () => { this.updateDuration(); });
        this.on(player, 'loadedmetadata', () => { this.throttle(() => this.updateDuration(), 25); });

        this.on('dispose', () => {
            ReactDOM.unmountComponentAtNode(this.el());
        });
    }

    public mount() {
        ReactDOM.render(<VideoPlayerInfo
            vjsComponent={this}
            title={this.specificOptions.title}
            displayTime={this.specificOptions.displayTime}
            currentTime={this.currentTime}
            currentDuration={this.currentDuration} />, this.el());
    }

    public updateContent() {
        const time = (this.player_.scrubbing()) ? this.player_.getCache().currentTime : this.player_.currentTime();
        const formattedTime = this.formatTime(time);
        this.currentTime = formattedTime;
        this.updateComponent();
    }

    private updateDuration() {
        const duration = this.player_.duration();
        if (this.cachedDuration !== duration) {
            this.cachedDuration = duration;
            this.currentDuration = this.formatTime(duration);
            this.updateComponent();
        }
    }

    private handleEnded() {
        if (!this.player_.duration()) {
            return;
        }
        const formattedTime = this.formatTime(this.player_.duration());
        this.currentTime = formattedTime;
        this.updateComponent();
    }

    private updateComponent() {
        ReactDOM.render(<VideoPlayerInfo
            vjsComponent={this}
            title={this.specificOptions.title}
            currentTime={this.currentTime}
            currentDuration={this.currentDuration}
            displayTime={this.specificOptions.displayTime} />, this.el());
    }

    private formatTime(totalSeconds: number) {
        totalSeconds = totalSeconds < 0 ? 0 : totalSeconds;
        const seconds = Math.floor(totalSeconds % 60);
        const minutes = Math.floor(totalSeconds / 60 % 60);
        const hours = Math.floor(totalSeconds / 3600);

        let secondsString = String(seconds);
        let minutesString = String(minutes);
        let hoursString = String(hours);

        if (isNaN(totalSeconds) || totalSeconds === Infinity) {
            hoursString = minutesString = secondsString = '-';
        } else {
            hoursString = (hours > 0) ? hours + ':' : '';
            minutesString = ((hours && minutes < 10) ? '0' + minutes : minutes) + ':';
            secondsString = (seconds < 10) ? '0' + seconds : secondsString;
        }

        return hoursString + minutesString + secondsString;
    }

    private throttle(fn: any, wait: number): any {
        let last = Date.now();
        const throttled = (...args: any[]) => {
            const now = Date.now();
            if (now - last >= wait) {
                fn(...args);
                last = now;
            }
        };
        return throttled;
    }
}

vjsComponent.registerComponent(VjsVideoPlayerInfo.ComponentName, VjsVideoPlayerInfo);

export default VjsVideoPlayerInfo;