<script setup lang="ts">
import { computed, ref, watch, watchEffect } from "vue";
import type { Ref } from "vue";

import TreeSelect from "primevue/treeselect";
import type { TreeNode } from "primevue/treenode";

import { fetchConceptsTree } from "@/arches_component_lab/datatypes/concept/api.ts";
import { convertConceptOptionToFormValue } from "@/arches_component_lab/datatypes/concept/utils.ts";

import type {
    CollectionItem,
    ConceptValue,
    ConceptFetchResult,
} from "@/arches_component_lab/datatypes/concept/types.ts";
import type { CardXNodeXWidgetData } from "@/arches_component_lab/types.ts";

const {
    graphSlug,
    nodeAlias,
    aliasedNodeData,
    cardXNodeXWidgetData,
    shouldEmitSimplifiedValue = false,
} = defineProps<{
    graphSlug: string;
    nodeAlias: string;
    aliasedNodeData: ConceptValue | null;
    cardXNodeXWidgetData: CardXNodeXWidgetData;
    shouldEmitSimplifiedValue?: boolean;
}>();

const emit = defineEmits<{
    (event: "update:value", updatedValue: ConceptValue | string | null): void;
    (event: "update:isLoading", isLoading: boolean): void;
}>();

const options: Ref<CollectionItem[] | null> = ref<CollectionItem[] | null>(
    null,
);
const isLoading = ref(false);
const optionsLoaded = ref(false);
const optionsTotalCount = ref(0);
const fetchError = ref<string | null>(null);

const initialValue = computed<Record<string, boolean> | null>(
    (): Record<string, boolean> | null => {
        if (!aliasedNodeData?.node_value) return null;
        return { [aliasedNodeData.node_value]: true };
    },
);

watch(isLoading, (newValue) => {
    emit("update:isLoading", newValue);
});

watchEffect(() => {
    getOptions();
});

async function getOptions() {
    try {
        if (optionsLoaded.value) return;
        isLoading.value = true;

        const fetchedData: ConceptFetchResult = await fetchConceptsTree(
            graphSlug,
            nodeAlias,
        );

        options.value = fetchedData.results as CollectionItem[];

        optionsTotalCount.value = options.value.length;
    } catch (error) {
        fetchError.value = (error as Error).message;
    } finally {
        isLoading.value = false;
        optionsLoaded.value = true;
    }
}

function onUpdateModelValue(selectedOption: Record<string, boolean> | null) {
    const formattedValue = convertConceptOptionToFormValue(
        selectedOption,
        options.value ?? ([] as CollectionItem[]),
    );
    if (shouldEmitSimplifiedValue) {
        emit("update:value", formattedValue.node_value);
    } else {
        emit("update:value", formattedValue);
    }
}
</script>

<template>
    <TreeSelect
        :input-id="cardXNodeXWidgetData.node.alias"
        data-key="key"
        selection-mode="single"
        filter
        :fluid="true"
        :show-clear="true"
        :loading="isLoading"
        :model-value="initialValue"
        :options="options as TreeNode[]"
        :placeholder="cardXNodeXWidgetData.config.placeholder"
        :reset-filter-on-hide="true"
        @update:model-value="onUpdateModelValue"
    >
    </TreeSelect>
</template>
