// detail-dataset.component.ts
import { Component, Vue, Prop } from "vue-facing-decorator";
import { DbDataset } from "@/models/dataset";
import DatasetService from "../../services/dataset.service";
import { Subscription } from "rxjs";
import dayjs from "dayjs";
import advancedFormat from "dayjs/plugin/advancedFormat";
import VsInput from "@/components/vs-input/vs-input.vue";
import { Suggestion } from "@/models/dataset";
import { VUE_API } from "@/constants";
// import DataMetricsBadge from "data-metrics-badge/dist/data-metrics-badge.js";
// import DataMetricsBadge from "@/components/datacite/DataMetricsBadge.vue";
import Minimap from '@/components/minimap/Minimap.vue';
import * as L from 'leaflet';

@Component({
    name: "DatasetDetailComponent",
    components: {
        VsInput,
        Minimap
        // DataMetricsBadge, // Commented out but prepared for future use
    },
})
export default class DatasetDetailComponent extends Vue {
    @Prop()
    datasetId!: string; // datasetId is passed as a prop and is required.

    searchTerm: string | Suggestion = ""; // Search term used in the search functionality.
    private subscriptions: Array<Subscription> = []; // Subscriptions to RxJS observables to prevent memory leaks.
    public dataset = {} as DbDataset; // Holds dataset details.
    private error: string = ""; // Stores error messages, if any.
    public loaded = false; // Indicates whether the dataset is fully loaded.
    public openAccessLicences: Array<string> = ["CC-BY-4.0", "CC-BY-SA-4.0"]; // Available open-access licenses.
    public portal = VUE_API + "/api/file/download/"; // Portal URL for file downloads.

    // If needed for stats
    // public post = {
    //     views: 25,       // Number of views for the dataset
    //     downloads: 1262, // Number of downloads
    //     citations: 2424, // Number of citations
    // };

    /**
     * Lifecycle hook: Called when the component is created.
     * Extends dayjs with advanced format plugin and determines whether to
     * fetch dataset by ID or by DOI.
     */
    created(): void {
        dayjs.extend(advancedFormat); // Adds advanced date formatting options to dayjs.
        if (!this.datasetId.includes(".")) {
            // Fetch dataset by publish_id (numeric ID)
            this.getDataset(Number(this.datasetId));
        } else {
            // Fetch dataset by DOI (alphanumeric ID)
            this.getDatasetByIdentifier(this.datasetId);
        }
    }

    /**
     * Lifecycle hook: Called before the component is unmounted.
     * Unsubscribes from all subscriptions to prevent memory leaks.
     */
    beforeUnmount(): void {
        for (const subs of this.subscriptions) {
            subs.unsubscribe();
        }
    }

    /**
     * Handles search functionality based on user input or suggestion selection.
     * Opens a new window or navigates internally based on the host's domain.
     * @param suggestion - The suggestion or search term entered by the user.
     */
    onSearch(suggestion: Suggestion | string): void {        
        const host = window.location.host;
        const parts = host.split(".");
        if (parts[0] === "doi") {
            // If in DOI subdomain, open external search in a new window
            let term;
            if (typeof suggestion === "string") {
                term = suggestion;
                window.open("https://tethys.at/search/" + term, "_self");
            } else if (suggestion instanceof Suggestion) {
                term = suggestion.value;
                const type = suggestion.type;
                window.open("https://tethys.at/search/" + term + "/" + type, "_self");
            }
        } else {
            // Otherwise, route internally to search page
            let term;
            if (typeof suggestion === "string") {
                term = suggestion;
                this.$router.push({ name: "Search", params: { display: term } });
            } else if (suggestion instanceof Suggestion) {
                term = suggestion.value;
                this.$router.push({ name: "Search", params: { display: term, type: suggestion.type } });
            }
        }
    }

    /**
     * Fetches the dataset details by ID from the service and updates the component state.
     * @param id - The dataset's numeric ID.
     */
    private getDataset(id: number): void {
        const newSub = DatasetService.getDataset(id).subscribe({
            next: (res: DbDataset) => {
                this.dataset = res; // Store dataset in component state.
                this.loaded = true; // Mark as loaded.
            },
            error: (error: string) => {
                this.error = error; // Capture any errors during fetch.
            },
        });

        this.subscriptions.push(newSub); // Add subscription to array to manage unsubscribing later.
    }

    /**
     * Fetches the dataset details by DOI from the service and updates the component state.
     * @param id - The dataset's DOI (Digital Object Identifier).
     */
    private getDatasetByIdentifier(id: string): void {
        const newSub = DatasetService.getDatasetByDoi(id).subscribe({
            next: (res: DbDataset) => {
                this.dataset = res; // Store dataset in component state.
                this.loaded = true; // Mark as loaded.
            },
            error: (error: string) => this.errorHandler(error),
        });

        this.subscriptions.push(newSub); // Add subscription to array.
    }

    /**
     * Handles errors and updates the error message in the component.
     * @param err - Error message.
     */
    private errorHandler(err: string): void {
        this.error = err; // Update error message.
    }

    /**
     * Navigates back by one page in the router history, similar to browser back.
     */
    public goBack(): void {
        this.$router.go(-1); // Go back one step in the browser history.
    }

    /**
     * Extracts the file extension from a given filename.
     * @param filename - The name of the file.
     * @returns The file extension as a string.
     */
    public getExtension(filename: string): string {
        return filename.substring(filename.lastIndexOf(".") + 1, filename.length) || filename;
    }

    /**
     * Formats the file size into a human-readable string with appropriate units.
     * @param file_size - The size of the file in bytes.
     * @returns The formatted file size string.
     */
    public formatSize(file_size: number): string {
        let size = file_size;
        const unit = ["Byte", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"]; // Units for size.
        let i;
        for (i = 0; size >= 1024 && i < unit.length - 1; i++) {
            size = size / 1024; // Convert size to appropriate unit.
        }
        return Math.round((size + Number.EPSILON) * 100) / 100 + " " + unit[i];
    }

    /**
     * Formats a given date into a human-readable string with the full day, month, and year.
     * @param date - The date string to format.
     * @returns The formatted date string.
     */
    public getPublishedDate(date: string): string {
        return dayjs(date).format("ddd, MMMM Do, YYYY h:mm a");
    }

    /**
     * Formats a given date into a simpler "DD.MM.YYYY HH:mm" format.
     * @param date - The date string to format.
     * @returns The formatted date string.
     */
    public getHumanDate(date: string): string {
        return dayjs(date).format("DD.MM.YYYY HH:mm");
    }

    /**
     * Extracts the year from a given date string.
     * @param date - The date string to extract the year from.
     * @returns The year as a string.
     */
    public getYear(date: string): string {
        return dayjs(date).format("YYYY");
    }

    /**
     * Returns the human-readable language string based on the language code.
     * @param language - The language code (e.g., "de" for German).
     * @returns The language name as a string.
     */
    public getLanguage(language: string): string {
        if (language === "de") {
            return "Deutsch";
        } else {
            return "English";
        }
    }

    /**
     * Generates a citation string for the dataset based on its authors and publication details.
     * @returns The citation as a string.
     */
    public getCitation(): string {
        let citation = this.dataset.authors
            .map((u) => {
                let name = u.last_name;
                if (u.first_name) {
                    name += ", " + u.first_name?.substring(0, 1).toUpperCase() + ".";
                }
                return name;
            })
            .join(", ");
        citation += " (" + dayjs(this.dataset.server_date_published).format("YYYY") + "): ";
        citation += this.dataset.MainTitle?.value;
        citation += ". " + this.dataset.creating_corporation + ", ";
        citation += this.dataset.publisher_name;
        citation += ", Wien";
        return citation;
    }

    
}
