import cloneDeep from 'lodash-es/cloneDeep.js';
import { useCallback, useEffect, useState } from 'react';
import { useCreateTableName, useHandleStepOutputChanged, useHandleStepSave, useModalState, useStaticValue } from '../hooks/index.js';
export function useOnDuplicateStep(graph, table, onSave) {
    const createTableName = useCreateTableName(graph);
    const argsDuplicator = useArgsDuplicator();
    return useCallback((step)=>{
        const outputTable = table ?? graph?.latestForNodeId(step.id)?.table;
        onSave?.({
            ...step,
            id: undefined,
            args: argsDuplicator(step, outputTable?.columnNames()),
            input: cloneDeep(step.input)
        }, createTableName(graph.outputNameForNode(step.id) ?? step.id));
    }, [
        onSave,
        argsDuplicator,
        graph,
        table,
        createTableName
    ]);
}
/**
 * A hook to get the onEditStep callback
 *
 * @param setStep - The step setter
 * @param setStepIndex - The step-index setter
 * @param showTableModal - A callback to show the table modas
 * @returns
 */ export function useOnEditStep(setStep, setStepIndex, showTableModal) {
    return useCallback((step, index)=>{
        setStep(step);
        setStepIndex(index);
        showTableModal();
    }, [
        setStep,
        showTableModal,
        setStepIndex
    ]);
}
export function useOnCreateStep(index, dismissModal, save, selectOutput) {
    return useCallback((step, output)=>{
        save(step, output, index);
        dismissModal();
        if (output) selectOutput?.(output);
    }, [
        save,
        dismissModal,
        index,
        selectOutput
    ]);
}
/**
 *
 * @param graph - The graph manager
 * @returns A callback to use when saving a step, either new or existing
 */ export function useOnSaveStep(graph) {
    const updateStep = useHandleStepSave(graph);
    const updateStepOutput = useHandleStepOutputChanged(graph);
    return useCallback((step, output, index)=>{
        const stepResult = updateStep(step, index);
        updateStepOutput(stepResult, output);
    }, [
        updateStepOutput,
        updateStep
    ]);
}
/**
 * A hook to manage state for showing the the step transformation modal
 *
 * @param setStep - A mutator for the selected step
 * @param setStepIndex - A mutator for the selected step indexw
 * @returns An object containing the isOpen state, and show/hide callbacks
 */ export function useTransformModalState(setStep, setStepIndex) {
    const onDismiss = useCallback(()=>{
        setStep(undefined);
        setStepIndex(undefined);
    }, [
        setStep,
        setStepIndex
    ]);
    return useModalState(undefined, onDismiss);
}
export function useEditorTarget(stepIndex) {
    const addStepButtonId = useStaticValue(`button-${Math.round(Math.random() * 3)}`);
    const [editorTarget, setEditorTarget] = useState(addStepButtonId);
    useEffect(()=>{
        if (stepIndex !== undefined) {
            setEditorTarget(`.step-card-${stepIndex}`);
        } else {
            setEditorTarget(`#${addStepButtonId}`);
        }
    }, [
        addStepButtonId,
        stepIndex
    ]);
    return {
        editorTarget,
        addStepButtonId
    };
}
export function useOnDeleteStep(graph) {
    return useCallback((index)=>{
        graph.removeStep(index);
    }, [
        graph
    ]);
}
function useArgsDuplicator() {
    const createColumnName = useCreateColumnName();
    return useCallback((step, columnNames)=>{
        const args = cloneDeep(step.args);
        // if there's a single-column to-field, find a unique name for it
        if (args['to'] && typeof args['to'] === 'string') {
            args['to'] = createColumnName(args['to'], columnNames);
        }
        return args;
    }, [
        createColumnName
    ]);
}
function useCreateColumnName() {
    const verifyColumnName = useCallback((name, columnNames)=>{
        return columnNames?.includes(name) ?? false;
    }, []);
    return useCallback((name, columnNames)=>{
        const originalName = name.replace(/( \(\d+\))/, '');
        let derivedName = originalName;
        let count = 1;
        while(verifyColumnName(derivedName, columnNames)){
            derivedName = `${originalName} (${count})`;
            count++;
        }
        return derivedName;
    }, [
        verifyColumnName
    ]);
}
export function useDeleteConfirm(onDelete) {
    const { isOpen , show , hide , toggle  } = useModalState(undefined, undefined);
    const [deleteArg, setDeleteArg] = useState();
    const onDeleteClicked = useCallback((args)=>{
        setDeleteArg(args);
        show();
    }, [
        show,
        setDeleteArg
    ]);
    const onConfirmDelete = useCallback(()=>{
        onDelete?.(deleteArg);
        hide();
    }, [
        hide,
        deleteArg,
        onDelete
    ]);
    return {
        isOpen,
        toggle,
        onConfirm: onConfirmDelete,
        onClick: onDeleteClicked
    };
}
export function useGraphOutputListener(graph, setOutput) {
    useEffect(()=>setOutput && graph.onChange(()=>setOutput(graph.toList().filter((t)=>!!t))), [
        graph,
        setOutput
    ]);
}
export function useGraphWorkflowListener(graph, setWorkflow) {
    useEffect(()=>setWorkflow && graph.onChange(()=>setWorkflow(graph.workflow)), [
        graph,
        setWorkflow
    ]);
}
