// Based of https://github.com/GilgusMaximus/yt-dash-manifest-generator/blob/master/src/DashGenerator.js

import { Buffer } from "buffer";
window.Buffer = Buffer;
import { json2xml } from "xml-js";

const DashUtils = {
    generate_dash_file_from_formats(VideoFormats, VideoLength) {
        const generatedJSON = this.generate_xmljs_json_from_data(VideoFormats, VideoLength);
        return json2xml(generatedJSON);
    },
    generate_xmljs_json_from_data(VideoFormatArray, VideoLength) {
        const convertJSON = {
            declaration: {
                attributes: {
                    version: "1.0",
                    encoding: "utf-8",
                },
            },
            elements: [
                {
                    type: "element",
                    name: "MPD",
                    attributes: {
                        xmlns: "urn:mpeg:dash:schema:mpd:2011",
                        profiles: "urn:mpeg:dash:profile:full:2011",
                        minBufferTime: "PT1.5S",
                        type: "static",
                        mediaPresentationDuration: `PT${VideoLength}S`,
                    },
                    elements: [
                        {
                            type: "element",
                            name: "Period",
                            elements: this.generate_adaptation_set(VideoFormatArray),
                        },
                    ],
                },
            ],
        };
        return convertJSON;
    },
    generate_adaptation_set(VideoFormatArray) {
        const adaptationSets = [];
        const mimeTypes = [];
        const mimeObjects = [[]];
        // sort the formats by mime types
        VideoFormatArray.forEach(videoFormat => {
            // the dual formats should not be used
            if (videoFormat.mimeType.indexOf("video") != -1 && !videoFormat.videoOnly) {
                return;
            }
            // if these properties are not available, then we skip it because we cannot set these properties
            //if (!(videoFormat.hasOwnProperty('initRange') && videoFormat.hasOwnProperty('indexRange'))) {
            //   return
            //}
            const mimeType = videoFormat.mimeType;
            const mimeTypeIndex = mimeTypes.indexOf(mimeType);
            if (mimeTypeIndex > -1) {
                mimeObjects[mimeTypeIndex].push(videoFormat);
            } else {
                mimeTypes.push(mimeType);
                mimeObjects.push([]);
                mimeObjects[mimeTypes.length - 1].push(videoFormat);
            }
        });
        // for each MimeType generate a new Adaptation set with Representations as sub elements
        for (let i = 0; i < mimeTypes.length; i++) {
            let isVideoFormat = false;
            const adapSet = {
                type: "element",
                name: "AdaptationSet",
                attributes: {
                    id: i,
                    mimeType: mimeTypes[i],
                    startWithSAP: "1",
                    subsegmentAlignment: "true",
                },
                elements: [],
            };
            if (!mimeTypes[i].includes("audio")) {
                adapSet.attributes.scanType = "progressive";
                isVideoFormat = true;
            }
            mimeObjects[i].forEach(format => {
                if (isVideoFormat) {
                    adapSet.elements.push(this.generate_representation_video(format));
                } else {
                    adapSet.elements.push(this.generate_representation_audio(format));
                }
            });
            adaptationSets.push(adapSet);
        }
        return adaptationSets;
    },
    generate_representation_audio(Format) {
        const representation = {
            type: "element",
            name: "Representation",
            attributes: {
                id: Format.itag,
                codecs: Format.codec,
                bandwidth: Format.bitrate,
            },
            elements: [
                {
                    type: "element",
                    name: "AudioChannelConfiguration",
                    attributes: {
                        schemeIdUri: "urn:mpeg:dash:23003:3:audio_channel_configuration:2011",
                        value: "2",
                    },
                },
                {
                    type: "element",
                    name: "BaseURL",
                    elements: [
                        {
                            type: "text",
                            text: Format.url,
                        },
                    ],
                },
                {
                    type: "element",
                    name: "SegmentBase",
                    attributes: {
                        indexRange: `${Format.indexStart}-${Format.indexEnd}`,
                    },
                    elements: [
                        {
                            type: "element",
                            name: "Initialization",
                            attributes: {
                                range: `${Format.initStart}-${Format.initEnd}`,
                            },
                        },
                    ],
                },
            ],
        };
        return representation;
    },
    generate_representation_video(Format) {
        const representation = {
            type: "element",
            name: "Representation",
            attributes: {
                id: Format.itag,
                codecs: Format.codec,
                bandwidth: Format.bitrate,
                width: Format.width,
                height: Format.height,
                maxPlayoutRate: "1",
                frameRate: Format.fps,
            },
            elements: [
                {
                    type: "element",
                    name: "BaseURL",
                    elements: [
                        {
                            type: "text",
                            text: Format.url,
                        },
                    ],
                },
                {
                    type: "element",
                    name: "SegmentBase",
                    attributes: {
                        indexRange: `${Format.indexStart}-${Format.indexEnd}`,
                    },
                    elements: [
                        {
                            type: "element",
                            name: "Initialization",
                            attributes: {
                                range: `${Format.initStart}-${Format.initEnd}`,
                            },
                        },
                    ],
                },
            ],
        };
        return representation;
    },
};

export default DashUtils;
