import { transformAndValidateSync } from "class-transformer-validator";
import { INavTree, IPageContent, ISection } from "../Types";
import { Resource } from "./Resource";

export class Content extends Resource {
    private nav_tree_cache: Record<string, INavTree> = {};

    public async getPageTitle(): Promise<string> {
        const response = await this.axios.get("/content/v1/pageTitle");
        return response.data;
    }

    public async getBannerText(): Promise<string[]> {
        const response = await this.axios.get("/content/v1/bannerText");
        const data = response.data.banner;
        return Array.isArray(data) ? data : [data];
    }
    public async getSectionsAndVersions(): Promise<string> {
        const response = await this.axios.get("/content/v1/sections");
        return response.data;
    }

    public async getSections(path?: string): Promise<ISection[]> {
        const params = {};
        if (path) {
            params["for-path"] = path;
        }
        const response = await this.axios.get(`structure`, {params});
        const sections = response.data.children;
        return sections.map(obj => {
            obj = this.fixMetadata(obj);
            transformAndValidateSync(ISection, obj);
            return obj;
        });
    }

    public async getAllGroups(): Promise<Record<string, ISection>> {
        const response = await this.axios.get(`groups`);

        const groups = response.data.groups;
        for (const key of Object.keys(groups)) {
            groups[key] = this.fixMetadata(groups[key]);
            transformAndValidateSync(ISection, groups[key]);
        }
        return groups;
    }

    public async getNamedGroup(group_name: string): Promise<ISection[]> {
        const groups = await this.getAllGroups();
        if (groups[group_name] === undefined) {
            return null;
        }
        return groups[group_name].children.map(child => this.fixMetadata(child));
    }

    public async getContentForResourceId(resource_id: string): Promise<IPageContent> {
        const params = {"for-resourceid": resource_id};
        const response = await this.axios.get(`content`, {params});

        const data = response.data;
        data.versions = data.otherVersions || [];
        data.current_version = data.thisVersion || "";
        data.page_type = data.outputclasses && data.outputclasses.length > 0 && data.outputclasses[0] ? "landing_page" : "content_page";

        transformAndValidateSync(IPageContent, data);

        return response.data;
    }

    public async getRedirect(path: string): Promise<string> {
        const response = await this.axios.get(`content`, {params: {"for-path": path}});
        return response.data.redirect ? response.data.redirect.href : null;
    }

    public async getContent(path?: string, audiences: string[] = []): Promise<IPageContent> {
        const params = {
            "audiences": audiences.join(","),
            "include-metadata": true,
        };
        if (path) {
            params["for-path"] = path;
        }
        const response = await this.axios.get(`content`, {params});

        const data = response.data;
        data.versions = data.otherVersions || [];
        data.current_version = data.thisVersion || "";
        data.page_type = data.outputclasses && data.outputclasses.length > 0 && data.outputclasses[0] ? "landing_page" : "content_page";

        transformAndValidateSync(IPageContent, data);

        return response.data;
    }

    public async getPrintContent(path?: string, audiences: string[] = []): Promise<string> {
        const params = {
            "audiences": audiences.join(","),
            "include-metadata": true,
            "full": true,
        };
        if (path) {
            params["for-path"] = path;
        }
        const response = await this.axios.get(`contentForPrint`, {params});
        return response.data.content;
    }

    public clearNavTreeCache() {
        this.nav_tree_cache = {};
    }

    public async getNavTree(path: string): Promise<INavTree> {
        const fixed_path = path.startsWith("/") ? path.slice(1) : path;
        const cache_key = fixed_path.split("/").slice(0,2).join("/");

        if (this.nav_tree_cache[cache_key]) {
            return this.nav_tree_cache[cache_key];
        }

        console.log(`NO CACHED TREE FOR ${cache_key}`);

        const tree = (await this.axios.get("structure", { params: { "for-path": cache_key } })).data;
        transformAndValidateSync(INavTree, tree);
        this.nav_tree_cache[cache_key] = tree;
        // return this.nav_tree_cache[cache_key];
        return tree;
    }

    private fixMetadata(section: any): ISection {
        // TECH DEBT: m should never be null, but we still have to check in the conditional?
        const thumbnails = section.meta.filter(m => m && m.name === "thumbnail");
        if (thumbnails.length > 0) {
            section.thumbnail = thumbnails[0].href;
            section.meta = section.meta.filter(m => m && m.name !== "thumbnail");
        }
        return section;
    }
}
