import { TreeQueryInput, TreeOptionType, FetcherResponse } from '@box/combobox-with-api';
import type API from '../../../api';
import type { MetadataOptionEntry } from '../../../common/types/metadata';

export const metadataTaxonomyFetcher = async (
    api: API,
    fileId: string,
    scope: string,
    templateKey: string,
    fieldKey: string,
    level: number,
    options: TreeQueryInput,
): Promise<FetcherResponse<TreeOptionType>> => {
    const metadataOptions = await api
        .getMetadataAPI(false)
        .getMetadataOptions(fileId, scope, templateKey, fieldKey, level, options);
    const { marker = null } = options;

    return {
        options: metadataOptions.entries.map((metadataOption: MetadataOptionEntry) => ({
            value: metadataOption.id,
            displayValue: metadataOption.display_name || metadataOption.displayName,
            level: metadataOption.level,
            parentId: metadataOption.parentId,
            nodePath: metadataOption.nodePath,
            deprecated: metadataOption.deprecated,
            ancestors: metadataOption.ancestors?.map(({display_name, displayName, ...rest}) => ({...rest, displayName: display_name || displayName })),
            selectable: metadataOption.selectable,
        })),
        marker,
        ...(metadataOptions.total_result_count !== undefined && { totalResultCount: metadataOptions.total_result_count }),
        ...(metadataOptions.limit !== undefined && { limit: metadataOptions.limit }),
    } as FetcherResponse<TreeOptionType>;
};

type HydratedMetadataTaxonomyLevel = {
    level: number;
    levelName: string;
    description: string;
    levelValue: string;
    id: string;
};

export const metadataTaxonomyNodeAncestorsFetcher = async (
    api: API,
    fileID: string,
    scope: string,
    taxonomyKey: string,
    nodeID: string,
): Promise<HydratedMetadataTaxonomyLevel[]> => {
    const [metadataTaxonomy, metadataTaxonomyNode] = await Promise.all([
        api.getMetadataAPI(false).getMetadataTaxonomy(fileID, scope, taxonomyKey),
        api.getMetadataAPI(false).getMetadataTaxonomyNode(fileID, scope, taxonomyKey, nodeID, true),
    ]);

    if (!metadataTaxonomy?.levels) {
        return [];
    }

    // Create a hashmap of levels to easily hydrate with data from metadataTaxonomyNode
    const levelsMap = new Map();
    for (const item of metadataTaxonomy.levels) {
        const levelData = {
            level: item.level,
            levelName: item.displayName || item.display_name,
            description: item.description,
        };

        // If the level matches the metadataTaxonomyNode level, hydrate the level with the node data
        if (metadataTaxonomyNode.level === item.level) {
            levelsMap.set(item.level, {
                ...levelData,
                id: metadataTaxonomyNode.id,
                levelValue: metadataTaxonomyNode.displayName || metadataTaxonomyNode.display_name,
            });
            // If the level is not the metadataTaxonomyNode level, just add the level data
        } else {
            levelsMap.set(item.level, levelData);
        }
    }
    // Hydrate the levels with the ancestors data from the metadataTaxonomyNode
    if (metadataTaxonomyNode.ancestors?.length) {
        for (const ancestor of metadataTaxonomyNode.ancestors) {
            const levelData = levelsMap.get(ancestor.level);

            if (levelData) {
                levelsMap.set(ancestor.level, { ...levelData, levelValue: ancestor.displayName || ancestor.display_name, id: ancestor.id });
            }
        }
    }

    // Filter out levels that were not hydrated by metadataTaxonomyNode
    const hydratedLevels = Array.from(levelsMap.values()).filter(level => !!level.id);

    // Return the hydrated levels as an array
    return hydratedLevels;
};
