import { Transform } from '@viamrobotics/sdk';
import { getContext, setContext } from 'svelte';
import { createTransformFromFrame } from '../frame';
import { useEnvironment } from './useEnvironment.svelte';
import { usePartConfig } from './usePartConfig.svelte';
const key = Symbol('config-frames-context');
export const provideConfigFrames = () => {
    const environment = useEnvironment();
    const partConfig = usePartConfig();
    $effect(() => {
        environment.current.viewerMode = partConfig.isDirty ? 'edit' : 'monitor';
    });
    const [configFrames, configUnsetFrameNames] = $derived.by(() => {
        const { components } = partConfig.current;
        const results = {};
        const unsetResults = [];
        for (const { name, frame } of components ?? []) {
            if (!frame) {
                unsetResults.push(name);
                continue;
            }
            results[name] = createTransformFromFrame(name, frame);
        }
        return [results, unsetResults];
    });
    const [fragmentFrames, fragmentUnsetFrameNames] = $derived.by(() => {
        const { fragment_mods: fragmentMods = [] } = partConfig.current;
        const fragmentDefinedComponents = Object.keys(partConfig.componentNameToFragmentId);
        const results = {};
        const unsetResults = [];
        // deal with fragment defined components
        for (const fragmentComponentName of fragmentDefinedComponents || []) {
            const fragmentId = partConfig.componentNameToFragmentId[fragmentComponentName];
            const fragmentMod = fragmentMods?.find((mod) => mod.fragment_id === fragmentId);
            if (!fragmentMod) {
                continue;
            }
            const setComponentModIndex = fragmentMod.mods.findLastIndex((mod) => mod['$set']?.[`components.${fragmentComponentName}.frame`] !== undefined);
            const unsetComponentModIndex = fragmentMod.mods.findLastIndex((mod) => mod['$unset']?.[`components.${fragmentComponentName}.frame`] !== undefined);
            if (setComponentModIndex < unsetComponentModIndex) {
                unsetResults.push(fragmentComponentName);
            }
            else if (unsetComponentModIndex < setComponentModIndex) {
                const frameData = fragmentMod.mods[setComponentModIndex]['$set'][`components.${fragmentComponentName}.frame`];
                results[fragmentComponentName] = createTransformFromFrame(fragmentComponentName, frameData);
            }
        }
        return [results, unsetResults];
    });
    const frames = $derived.by(() => {
        const result = {
            ...configFrames,
            ...fragmentFrames,
        };
        return result;
    });
    const frameValues = $derived(Object.values(frames));
    const getParentFrameOptions = (componentName) => {
        const validFrames = new Set(frameValues.map((frame) => frame.referenceFrame));
        validFrames.add('world');
        const frameNameQueue = [componentName];
        while (frameNameQueue.length > 0) {
            const frameName = frameNameQueue.shift();
            if (frameName) {
                validFrames.delete(frameName);
                const filteredFrames = frameValues.filter((frame) => frame.poseInObserverFrame?.referenceFrame === frameName);
                for (const frame of filteredFrames) {
                    frameNameQueue.push(frame.referenceFrame);
                }
            }
        }
        return [...validFrames];
    };
    const unsetFrames = $derived([...new Set([...configUnsetFrameNames, ...fragmentUnsetFrameNames])]);
    setContext(key, {
        getParentFrameOptions,
        get unsetFrames() {
            return unsetFrames;
        },
        get current() {
            return frames;
        },
    });
};
export const useConfigFrames = () => {
    return getContext(key);
};
