<template>
    <v-app :theme="theme">
        <v-img
            v-bind:src="backgroundImage"
            width="100vw"
            height="100vh"
            cover
            class="bg-image"
        ></v-img>
        <v-app-bar app>
            <v-app-bar-title class="headline text-uppercase" v-if="smAndUp">
                <span v-if="appData.net !== '' && mdAndUp">{{ appData.net }}:</span>
                <span class="font-weight-light">{{ appData.name }}</span>
            </v-app-bar-title>

            <v-tabs
                v-model="activeTab"
                centered
            >
                <v-tab ripple to="/authors">{{ $t("authors") }}</v-tab>
                <v-tab ripple to="/books">{{ $t("books") }}</v-tab>
                <v-tab ripple to="/book">{{ $t("book") }}</v-tab>
            </v-tabs>

            <v-spacer></v-spacer>
<!--
            <v-btn
                :icon="theme == 'light' ? 'mdi-weather-night' : 'mdi-weather-sunny'"
                @click="toggleTheme"
            ></v-btn>
-->
            <v-btn
                icon="mdi-cog-outline"
                @click="showSettings"
            ></v-btn>
        </v-app-bar>

        <v-progress-linear
            indeterminate
            color="blue"
            v-if="showProgress"
        ></v-progress-linear>

        <v-main>
            <v-container fluid class="ma-0 pa-0">
                <router-view v-slot="{ Component }"
                    ref="view"
                    @authorSelected="loadBooks"
                    @bookSelected="loadBook"
                    @loadChapter="loadChapter"
                >
                    <!--
                    <transition name="scroll-x-transition">
                        <component :is="Component"/>
                    </transition>
                    -->
                    <component :is="Component"/>
                </router-view>
                <v-alert
                    prominent
                    closable
                    close-label="Close Alert"
                    :type="alertType"
                    v-if="alertMessage.trim() !== ''"
                    class="bottom-alert mx-2"
                >
                    {{ alertMessage }}
                </v-alert>
            </v-container>
        </v-main>

        <v-footer app height="95" style="bottom: 0" class="pa-0 ma-0 d-flex flex-wrap">
            <v-row class="w-100 pa-0 ma-0" style="flex-wrap: nowrap;">
                <v-col cols="12" class="py-0 my-0">
                    <v-slider
                        v-model="progress"
                        color="blue"
                        min="0"
                        max="100"
                        dense
                        hide-details
                        :disabled="isOff"
                        class="time-slider w-100 px-2 py-0 m-0"
                    >
                        <template v-slot:append>{{ currentTime ? currentTime : "00:00"}}/{{duration ? duration : "00:00"}}</template>
                    </v-slider>
                </v-col>
            </v-row>
            <v-row no-gutters class="w-100 pa-0 ma-0" style="flex-wrap: nowrap;">
                <v-col
                    cols="1"
                    style="min-width: 0px; max-width: 100%"
                    class="flex-grow-1 flex-shrink-0; background-color: red;"
                    v-if="smAndUp"
                >
                    <v-card flat color="rgba(0, 0, 0, 0)">
                        <v-list-item two-line>
                            <v-list-item-header>
                                <v-list-item-title>{{ $store.getters.book.author }}</v-list-item-title>
                                <v-list-item-subtitle style="overflow: hidden; white-space: nowrap; text-overflow: ellipsis;">{{ $store.getters.book.title }}<span v-if="$store.getters.chapters.length > 0 && currentChapter !== null && $store.getters.chapters[currentChapter].title !== ''"> - {{ $store.getters.chapters[currentChapter].title }}</span></v-list-item-subtitle>
                            </v-list-item-header>
                        </v-list-item>
                    </v-card>
                </v-col>
                <v-col
                    cols="6"
                    sm="4"
                    md="2"
                    class="flex-grow-1 flex-shrink-0 d-flex justify-center"
                    style="min-width: 220px;"
                >
                    <v-btn
                        flat
                        icon="mdi-skip-backward"
                        class="ml-1"
                        @click="prevChapter"
                    >
                    </v-btn>
                    <v-btn
                        flat
                        icon
                        class="ml-1"
                        @click="toggleStatus"
                    >
                        <v-icon>mdi-{{ isPlaying ? "pause" : "play" }}</v-icon>
                    </v-btn>
                    <v-btn
                        flat
                        icon="mdi-skip-forward"
                        class="ml-1"
                        @click="nextChapter"
                    ></v-btn>
                    <v-btn
                        flat
                        icon="mdi-bookmark-outline"
                        class="ml-1"
                        @click="setBookmark(false)"
                        v-if="!$store.getters.autoBookmark"
                    ></v-btn>
                </v-col>
                <v-col
                    cols="6"
                    sm="4"
                    md="3"
                    lg="2"
                    class="flex-grow-1 flex-shrink-0 pt-2 pr-6"
                    style="min-width: 100px;"
                >
                    <v-slider
                        class="w-100"
                        :class="{ 'mr-3': mdAndUp, 'ml-3': mdAndDown }"
                        :min="0"
                        :max="10"
                        thumb-label
                        hide-details
                        color="blue"
                        v-model="volume"
                        prepend-icon="mdi-volume-low"
                        append-icon="mdi-volume-high"
                    ></v-slider>
                </v-col>
            </v-row>
        </v-footer>
        <!--
        <v-fab-transition>
            <v-btn
                class="to-top-button"
                v-show="scrolled"
                color="blue"
                @click="scrollToTop"
                dark
                fixed
                bottom
                right
                fab
            >
                <v-icon>keyboard_arrow_up</v-icon>
            </v-btn>
        </v-fab-transition>
        -->
        <message-box ref="MessageBox"/>
        <settings-dialog ref="SettingsDialog"/>
    </v-app>
</template>

<script>
    //import { ref, onMounted } from "vue";
    import { ref }        from "vue";
    import { useDisplay } from "vuetify";
    import MessageBox     from "./components/MessageBox";
    import SettingsDialog from "./components/SettingsDialog";

    export default {
        name: "App",
        components: {
            MessageBox,
            SettingsDialog,
        },

        setup () {
            const theme = ref("light");
            const { smAndDown, smAndUp, mdAndUp, mdAndDown } = useDisplay();

            /*
            onMounted (() => {
                console.log("on mounted");
            })
            */

            return {
                theme,
                smAndDown,
                smAndUp,
                mdAndUp,
                mdAndDown,
                setTheme: (newTheme) => theme.value = newTheme === "light" || newTheme === "dark" ? newTheme : "light",
                toggleTheme: () => theme.value = theme.value === "light" ? "dark" : "light",
            }
        },

        data () {
            return {
                activeTab:       0,
                appData:         { name: "", net: "" },
                backgroundImage: this.defaultBackground,

                alertType:       "info",
                alertMessage:    "",

                loading: {
                    authors: false,
                    books:   false,
                    book:    false,
                    wiki:    false,
                },

                authors:         [],

                audioElement:    null,
                currentChapter:  null,
                currentProgress: 0,
                currentTime:     "00:00",
                playbackRate:    1,
                status:          0,
                volume:          5,

                scrolled:        false,
                useWikipedia:    true,
            }
        },

        watch: {
            "$route" (to) {
                if (to.path == "/authors") {
                    this.activeTab = this.tabs.authors;
                } else if (to.path == "/books") {
                    this.activeTab = this.tabs.books;
                } else if (to.path == "/book") {
                    this.activeTab = this.tabs.book;
                }
            },

            "$store.getters.autoBookmark" (val) {
                localStorage.autoBookmark = val;
            },

            "$store.getters.autoLoadBooks" (val) {
                localStorage.autoLoadBooks = val;
            },

            "$store.getters.darkTheme" (val) {
                this.setTheme(val == true ? "dark" : "light");
                localStorage.darkTheme = val;
            },

            "$store.getters.playbackRate" (val) {
                this.playbackRate = val;
                localStorage.playbackRate = val;
            },

            alertMessage (val) {
                if (val.trim() !== "") {
                    setTimeout(() => { this.alertMessage = ""; }, 5000);
                }
            },

            playbackRate (val) {
                if (this.audioElement !== null) {
                    this.audioElement.playbackRate = val;
                }
            },

            volume (val) {
                this.updateVolume();
                localStorage.volume = val;
            }
        },

        computed: {
            isOff () {
                return this.audioElement == null;
            },

            isPaused () {
                return this.status === this.statuses.paused;
            },

            isPlaying () {
                return this.status === this.statuses.playing;
            },

            isChapterLoaded () {
                return (this.currentChapter !== null) && this.audioElement;
            },

            progress: {
                get () {
                    return this.currentProgress;
                },

                set (val) {
                    if (this.audioElement !== null && val !== Math.round(this.currentProgress)) {
                        this.currentProgress = val;
                        this.audioElement.currentTime = this.audioElement.duration * val / 100;
                    }
                }
            },

            showProgress () {
                return this.loading.authors || this.loading.books || this.loading.book || this.loading.wiki;
            }
        },

        mounted () {
            let autoBookmark = localStorage.autoBookmark ? JSON.parse(localStorage.autoBookmark) : false;
            this.$store.commit("setAutoBookmark", autoBookmark);

            let autoLoadBooks = localStorage.autoLoadBooks ? JSON.parse(localStorage.autoLoadBooks) : false;
            this.$store.commit("setAutoLoadBooks", autoLoadBooks);

            let darkTheme = localStorage.darkTheme ? JSON.parse(localStorage.darkTheme) : false;
            this.$store.commit("setDarkTheme", darkTheme);

            let playbackRate = localStorage.playbackRate ? JSON.parse(localStorage.playbackRate) : 1;
            this.$store.commit("setPlaybackRate", playbackRate);

            this.volume = localStorage.volume ? JSON.parse(localStorage.volume) : 5;

            this.appData.name = this.$t("appName");
            this.appData.net  = this.appConfig.appNet;

            if (this.$router.currentRoute._value.path == "/authors") {
                this.activeTab = this.tabs.authors;
            } else if (this.$router.currentRoute._value.path == "/books") {
                this.activeTab = this.tabs.books;
            } else if (this.$router.currentRoute._value.path == "/book") {
                this.activeTab = this.tabs.book;
            }

            //window.addEventListener("scroll", this.onScroll);

            this.loadAuthors();
        },

        unmounted () {
            //window.removeEventListener("scroll", this.onScroll);
        },

        methods: {
            fillWikiInfo (searchText, fillAuthorInfo = true) {
                this.loading.wiki = true;

                this.axios.get(`https://${this.$i18n.locale}.wikipedia.org/w/api.php`, {
                    params: {
                        format: "json",
                        action: "query",
                        prop: "extracts",
                        exintro: 1,
                        explaintext: 1,
                        redirects: 1,
                        titles: searchText,
                        origin: "*"
                    }
                }).then(response => {
                    if (Object.getOwnPropertyNames(response.data.query.pages)[0] > 0) {
                        let result = response.data.query.pages[
                            Object.getOwnPropertyNames(response.data.query.pages)[0]
                        ].extract;

                        if (fillAuthorInfo) {
                            let authorInfo  = this.$store.getters.author;
                            authorInfo.wiki = result;
                            this.$store.commit("setAuthor", authorInfo);
                        } else {
                            let bookInfo  = this.$store.getters.book;
                            bookInfo.wiki = result;
                            this.$store.commit("setBook", bookInfo);
                        }
                    } else {
                        if (fillAuthorInfo) {
                            let authorInfo  = this.$store.getters.author;
                            authorInfo.wiki = "";
                            this.$store.commit("setAuthor", authorInfo);
                        } else {
                            let bookInfo  = this.$store.getters.book;
                            bookInfo.wiki = "";
                            this.$store.commit("setBook", bookInfo);
                        }
                    }

                    this.loading.wiki = false;
                })
                .catch(error => {
                    this.loading.wiki = false;

                    if (fillAuthorInfo) {
                        let authorInfo  = this.$store.getters.author;
                        authorInfo.wiki = "";
                        this.$store.commit("setAuthor", authorInfo);
                    } else {
                        let bookInfo  = this.$store.getters.book;
                        bookInfo.wiki = "";
                        this.$store.commit("setBook", bookInfo);
                    }

                    console.error(error);
                });
            },

            getHash (val) {
                let CryptoJS = require("crypto-js");
                let hash     = CryptoJS.MD5(val);

                return hash.toString(CryptoJS.enc.Hex);
            },

            loadAuthors () {
                this.loading.authors = true;

                this.axios.get(`lib/authors.json?r=${Math.random()}`)
                    .then(response => {
                        let lastAuthorHash = localStorage.lastAuthor ? localStorage.lastAuthor : null;
                        let authors = [];
                        let authorToLoad = null;

                        response.data.forEach(author => {
                            let authorExt = author;
                            authorExt.hash = this.getHash(JSON.stringify({
                                author: authorExt.author,
                                books:  authorExt.books
                            }));
                            authors.push(authorExt);
                            if (lastAuthorHash !== null && lastAuthorHash == authorExt.hash) {
                                authorToLoad = { ...authorExt };
                            }
                        });

                        this.$store.commit("setAuthors", authors);

                        if (authorToLoad !== null && this.$store.getters.autoLoadBooks) {
                            this.loadBooks(authorToLoad);
                        }

                        this.loading.authors = false;
                    })
                    .catch(error => {
                        this.showMessage(this.$t("error"), error);
                        console.error(error);
                        this.loading.authors = false;
                    })
            },

            /**
            * Load book data
            *
            * @param {object}  bookData    Book data
            * @param {boolean} switchToTab Switch to Book tab after data loading
            */
            loadBook (bookData, switchToTab = false) {
                if (this.audioElement !== null && this.$store.getters.autoBookmark) {
                    this.setBookmark();
                }

                let author = this.$store.getters.author;

                this.$store.commit("setBook", {
                    author: author.name,
                    photo:  author.image,
                    cycle:  bookData.cycle !== undefined && bookData.cycle !== "no_cycle" && bookData.cycle.trim() !== ""
                        ? bookData.cycle
                        : "",
                    title:  bookData.title,
                    cover:  bookData.image,
                    reader: bookData.reader !== undefined && bookData.reader.trim() !== ""
                        ? bookData.reader
                        : "",
                    hash:   bookData.hash,
                    wiki:   ""
                });

                this.loading.book = true;

                this.axios.get(`${bookData.book}?r=${Math.random()}`)
                    .then(response => {
                        this.$store.commit("setChapters", response.data);

                        let bmKey    = this.getHash(JSON.stringify(this.$store.getters.chapters));
                        let bookmark = localStorage.getItem(bmKey) ? JSON.parse(localStorage.getItem(bmKey)) : null;

                        console.log(bmKey, bookmark);

                        if (bookmark !== null) {
                            this.loadChapter(bookmark.chapter, bookmark.progress);
                        } else {
                            this.loadChapter();
                        }

                        if (this.useWikipedia) {
                            this.fillWikiInfo(bookData.title, false);
                        }

                        this.backgroundImage = bookData.image;

                        if (switchToTab) {
                            this.$router.push({ path: "/book" });
                        }

                        this.loading.book = false;
                    })
                    .catch(error => {
                        this.loading.book = false;
                        this.showMessage(this.$t("error"), error);

                        console.error(error);
                    });
            },

            /**
            * Load books data
            *
            * @param {object}  authorData  Author data
            * @param {boolean} switchToTab Switch to Books tab after data loading
            */
            loadBooks (authorData, switchToTab = false) {
                this.loading.books = true;

                this.axios.get(`${authorData.books}?r=${Math.random()}`)
                    .then(response => {
                        let books = {};
                        let bookToLoad = null;

                        response.data.forEach((book) => {
                            let cycle = book.cycle !== undefined ? book.cycle : "no_cycle";

                            if (books[cycle] == undefined) {
                                books[cycle] = [];
                            }

                            let bookExt = { ...book };
                            bookExt.hash = this.getHash(JSON.stringify({
                                book: bookExt.book,
                            }));

                            books[cycle].push(bookExt);

                            if (localStorage[authorData.hash] && localStorage[authorData.hash] == bookExt.hash) {
                                bookToLoad = { ...bookExt };
                            }
                        });

                        this.$store.commit("setAuthor", {
                            name:  authorData.author || "",
                            image: authorData.image || "",
                            hash:  authorData.hash || "",
                            wiki:  ""
                        });

                        this.$store.commit("setBooks", books); // response.data);

                        if (this.useWikipedia) { this.fillWikiInfo(authorData.author); }

                        if (bookToLoad !== null && this.$store.getters.autoLoadBooks) {
                            this.loadBook(bookToLoad);
                        }

                        if (switchToTab) {
                            this.$router.push({ path: "/books" });
                        }

                        this.loading.books = false;
                    })
                    .catch(error => {
                        this.loading.books = false;
                        this.showMessage(this.$t("error"), error);

                        console.error(error);
                    })
            },

            loadChapter (index = 0, progress = 0, autoplay = false) {
                if (this.audioElement) { this.audioElement.pause(); }
                if (index >= this.$store.getters.chapters.length) { return false; } // show message?

                this.currentChapter = index;
                this.audioElement = new Audio(encodeURI(this.$store.getters.chapters[index].url));
                this.audioElement.playbackRate = this.playbackRate;

                this.$store.commit("setCurChapter", index);

                this.updateVolume();

                this.status = this.statuses.stopped;

                this.audioElement.addEventListener("ended", this.loadNextChapter);
                this.audioElement.ontimeupdate = this.updateProgress;

                let component = this;

                this.audioElement.addEventListener("durationchange", function () {
                    let min = parseInt(component.audioElement.duration / 60) < 10
                        ? "0" + parseInt(component.audioElement.duration / 60)
                        : parseInt(component.audioElement.duration / 60);
                    let sec = parseInt(component.audioElement.duration % 60) < 10
                        ? "0" + parseInt(component.audioElement.duration % 60)
                        : parseInt(component.audioElement.duration % 60);
                    component.duration = min + ":" + sec;
                });

                this.audioElement.addEventListener("canplay", function _listener () {
                    component.audioElement.currentTime = component.audioElement.duration * progress / 100;
                    component.audioElement.removeEventListener("canplay", _listener, true);
                }, true);

                if (autoplay) { this.play(); }
            },

            loadNextChapter (autoplay = true) {
                this.currentChapter++;
                if (this.currentChapter >= this.$store.getters.chapters.length) {
                    this.currentChapter--;
                    return false;
                }
                this.loadChapter(this.currentChapter, 0, autoplay);
            },

            nextChapter () {
                if (this.currentChapter < this.$store.getters.chapters.length - 1) {
                    this.currentChapter++;
                    this.loadChapter(this.currentChapter, 0, true);
                }
            },

            onScroll () {
                this.scrolled = window.scrollY > 0;
            },

            pause () {
                this.status = this.statuses.paused;
                this.audioElement.pause();
            },

            play () {
                this.status = this.statuses.playing;
                this.audioElement.play();
                localStorage.lastAuthor = this.$store.getters.author.hash;
                localStorage[this.$store.getters.author.hash] = this.$store.getters.book.hash;
            },

            prevChapter () {
                if (this.currentChapter > 0) {
                    this.currentChapter--;
                    this.loadChapter(this.currentChapter, 0, true);
                }
            },

            setBookmark (silent = true) {
                if (this.$store.getters.chapters.length == 0) { return; }

                let data = {
                    chapter:  this.$store.getters.curChapter,
                    progress: this.currentProgress
                };

                localStorage.setItem(
                    this.getHash(JSON.stringify(this.$store.getters.chapters)),
                    JSON.stringify(data)
                );

                if (!silent) { this.alertMessage = this.$t("bookmarkSaved"); }
            },

            showMessage (title, text) {
                this.$refs.MessageBox.title  = title;
                this.$refs.MessageBox.text   = text;
                this.$refs.MessageBox.dialog = true;
            },

            showSettings () {
                this.$refs.SettingsDialog.dialog = true;
            },

            toggleStatus () {
                if (!this.isChapterLoaded) {
                    this.loadChapter(this.currentChapter || 0);
                }

                if (!this.isPlaying) {
                    this.play();
                } else {
                    this.pause();

                    if (this.$store.getters.autoBookmark) {
                        this.setBookmark();
                    }
                }
            },

            updateProgress () {
                if (!this.audioElement || !this.audioElement.currentTime) {
                    return this.currentProgress = 0;
                }

                this.currentProgress = (this.audioElement.currentTime / this.audioElement.duration) * 100;

                let min = parseInt(this.audioElement.currentTime / 60) < 10
                    ? "0" + parseInt(this.audioElement.currentTime / 60)
                    : parseInt(this.audioElement.currentTime / 60);
                let sec = parseInt(this.audioElement.currentTime % 60) < 10
                    ? "0" + parseInt(this.audioElement.currentTime % 60)
                    : parseInt(this.audioElement.currentTime % 60);
                this.currentTime = min + ":" + sec;
            },

            updateVolume () {
                this.audioElement ? this.audioElement.volume = (this.volume / 10) : null;
            }
        }
    }
</script>

<style lang="sass">
    .bg-image
        position: absolute
        filter: blur(10px) opacity(30%) !important
        img
            opacity: 100% !important

    .loading-progress
        margin: auto 15px

    .player-interface
        position: fixed !important
        bottom: 0
        .time-slider
            margin-top: -25px

    .to-top-button
        margin-bottom: 80px

    .v-application.v-theme--
        &light
            header, footer, .semi-transparent
                background: rgba(255, 255, 255, .5)
        &dark
            header, footer, .semi-transparent
                background: rgba(15, 15, 15, .5)

    .content-container
        height: calc(100vh - 160px)
        overflow-y: auto
        overflow-x: hidden

    /* vuetify bugfix */
    .v-toolbar__content
        .v-tabs
            .v-btn
                height: inherit

    .bottom-alert
        position: absolute !important
        bottom: 5px
        left: 0
        right: 0
        z-index: 999
        opacity: .9
</style>
