import { IEntry, ListingResult } from "@/types/base";
import { fetcher } from "@/utils";
import useSWRV from "swrv";
import { computed, ComputedRef, Ref } from "vue";


export function useEntity(address: string | (() => string), condition?: () => Boolean) {
    const { data, error, mutate } = useSWRV<ListingResult, unknown>(
        () => (condition === undefined || condition()) ? `/api/obj/${typeof address === "string" ? address : address()}` : null,
        fetcher
    );

    const entries = computed(() => {
        if (data?.value) {
            const entries = Object.entries(data.value) as [string, IEntry][];
            return entries
                .sort(([_, a], [__, b]) => String(a.value.c).localeCompare(b.value.c))
                .sort(([_, a], [__, b]) => String(a.value.t).localeCompare(b.value.t))
                .sort(([_, a], [__, b]) => a.attribute.localeCompare(b.attribute));
        } else {
            return [];
        }
    });

    const attributes = computed(() => {
        const addr = typeof address === "string" ? address : address();
        return entries.value.filter(([_, e]) => e.entity === addr);
    });

    const backlinks = computed(() => {
        const addr = typeof address === "string" ? address : address();
        return entries.value.filter(([_, e]) => e.entity !== addr);
    });

    return {
        entries,
        attributes,
        backlinks,
        data,
        error,
        mutate
    }
}

interface EntityIdentification {
    type: string;
    value: string;
}

export function identify(attributes: ComputedRef<[string, IEntry][]>): ComputedRef<EntityIdentification[]> {
    // Get all identities of the object
    const isEntries = computed(() => {
        return attributes.value
            .filter(([_, entry]) => entry.attribute === "IS")
            .map(([_, entry]) => entry.value.c);
    })


    // Out of those, retrieve their TYPE_ID entries
    const { data: typeIdListing } = useSWRV<ListingResult, unknown>(() => {
        return isEntries.value && `/api/obj?query=(matches (in ${isEntries.value.map((e) => `"${e}"`).join(" ")}) "TYPE_ID" ?)`;
    }, fetcher);

    const typeIdAttributes: ComputedRef<[string, string][]> = computed(() => {
        return Object.values(typeIdListing.value || {}).map((entry) => {
            return [entry.entity, entry.value.c];
        });
    });



    // Finally, filter own object's attributes according to TYPE_IDs
    return computed(() => {
        // For each identity/TYPE_ID pair
        return typeIdAttributes.value
            .map(([type, attrName]) => {
                // And each associated TYPE_ID attribute...
                // return own matchin attributes
                return attributes.value
                    .filter(([_, e]) => e.attribute === attrName)
                    .map(([_, attr]) => {
                        return {
                            type,
                            value: attr.value.c
                        }
                    })
            }).flat();
    });
}