import React = require("react");
import axios from "axios";
import { action, computed } from "mobx";
import { observer } from "mobx-react";
import Waveform from "react-audio-waveform";
import { Doc } from "../../fields/Doc";
import { List } from "../../fields/List";
import { listSpec } from "../../fields/Schema";
import { Cast, NumCast } from "../../fields/Types";
import { numberRange } from "../../Utils";
import "./AudioWaveform.scss";
import { Colors } from "./global/globalEnums";

export interface AudioWaveformProps {
    duration: number;
    mediaPath: string;
    layoutDoc: Doc;
    trimming: boolean;
    PanelHeight: () => number;
}

@observer
export class AudioWaveform extends React.Component<AudioWaveformProps> {
    public static NUMBER_OF_BUCKETS = 100;
    @computed get _waveHeight() {
        return Math.max(50, this.props.PanelHeight());
    }
    componentDidMount() {
        const audioBuckets = Cast(
            this.props.layoutDoc.audioBuckets,
            listSpec("number"),
            []
        );
        if (!audioBuckets.length) {
            this.props.layoutDoc.audioBuckets = new List<number>([0, 0]); /// "lock" to prevent other views from computing the same data
            setTimeout(this.createWaveformBuckets);
        }
    }

    // decodes the audio file into peaks for generating the waveform
    createWaveformBuckets = async () => {
        axios({ url: this.props.mediaPath, responseType: "arraybuffer" }).then(
            (response) => {
                const context = new window.AudioContext();
                context.decodeAudioData(
                    response.data,
                    action((buffer) => {
                        const decodedAudioData = buffer.getChannelData(0);

                        const bucketDataSize = Math.floor(
                            decodedAudioData.length / AudioWaveform.NUMBER_OF_BUCKETS
                        );
                        const brange = Array.from(Array(bucketDataSize));
                        this.props.layoutDoc.audioBuckets = new List<number>(
                            numberRange(AudioWaveform.NUMBER_OF_BUCKETS).map(
                                (i: number) =>
                                    brange.reduce(
                                        (p, x, j) =>
                                            Math.abs(
                                                Math.max(p, decodedAudioData[i * bucketDataSize + j])
                                            ),
                                        0
                                    ) / 2
                            )
                        );
                    })
                );
            }
        );
    }

    @action
    createTrimBuckets = () => {
        const audioBuckets = Cast(
            this.props.layoutDoc.audioBuckets,
            listSpec("number"),
            []
        );

        const start = Math.floor(
            (NumCast(this.props.layoutDoc.clipStart) / this.props.duration) * 100
        );
        const end = Math.floor(
            (NumCast(this.props.layoutDoc.clipEnd) / this.props.duration) * 100
        );
        return audioBuckets.slice(start, end);
    }

    render() {
        const audioBuckets = Cast(
            this.props.layoutDoc.audioBuckets,
            listSpec("number"),
            []
        );

        return (
            <div className="audioWaveform">
                {this.props.trimming || !this.props.layoutDoc.clipEnd ? (
                    <Waveform
                        color={Colors.MEDIUM_BLUE}
                        height={this._waveHeight}
                        barWidth={0.1}
                        pos={this.props.duration}
                        duration={this.props.duration}
                        peaks={
                            audioBuckets.length === AudioWaveform.NUMBER_OF_BUCKETS
                                ? audioBuckets
                                : undefined
                        }
                        progressColor={Colors.MEDIUM_BLUE}
                    />
                ) : (
                        <Waveform
                            color={Colors.MEDIUM_BLUE}
                            height={this._waveHeight}
                            barWidth={0.1}
                            pos={this.props.duration}
                            duration={this.props.duration}
                            peaks={this.createTrimBuckets()}
                            progressColor={Colors.MEDIUM_BLUE}
                        />
                    )}
            </div>
        );
    }
}
