"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.deleteSelectedTimelineItems = exports.getTimelineSelectionAfterDeletingItems = exports.deleteSelectedTimelineItem = void 0;
const remotion_1 = require("remotion");
const call_api_1 = require("../call-api");
const NotificationCenter_1 = require("../Notifications/NotificationCenter");
const delete_selected_keyframe_1 = require("./delete-selected-keyframe");
const find_track_for_node_path_info_1 = require("./find-track-for-node-path-info");
const get_easing_selection_after_keyframe_delete_1 = require("./get-easing-selection-after-keyframe-delete");
const parse_keyframe_field_from_node_path_1 = require("./parse-keyframe-field-from-node-path");
const TimelineSelection_1 = require("./TimelineSelection");
const update_selected_easing_1 = require("./update-selected-easing");
const confirmDeletingDuplicatedSequences = (nodePathInfos, confirm) => {
    const duplicatedNodePathInfos = nodePathInfos.filter((nodePathInfo) => nodePathInfo.numberOfSequencesWithThisNodePath > 1);
    if (duplicatedNodePathInfos.length === 0) {
        return Promise.resolve(true);
    }
    if (duplicatedNodePathInfos.length === 1) {
        const [nodePathInfo] = duplicatedNodePathInfos;
        return confirm({
            title: 'Delete sequence?',
            message: 'This sequence is programmatically duplicated ' +
                nodePathInfo.numberOfSequencesWithThisNodePath +
                ' times in the code. Deleting removes all instances. Continue?',
            confirmLabel: 'Delete',
        });
    }
    return confirm({
        title: 'Delete sequences?',
        message: duplicatedNodePathInfos.length +
            ' selected sequences are programmatically duplicated in the code. Deleting removes all instances. Continue?',
        confirmLabel: 'Delete',
    });
};
const deleteSequences = async (nodePathInfos, confirm) => {
    if (!(await confirmDeletingDuplicatedSequences(nodePathInfos, confirm))) {
        return false;
    }
    return (0, call_api_1.callApi)('/api/delete-jsx-node', {
        nodes: nodePathInfos.map((nodePathInfo) => {
            const nodePath = nodePathInfo.sequenceSubscriptionKey;
            return {
                fileName: nodePath.absolutePath,
                nodePath: nodePath.nodePath,
            };
        }),
    })
        .then((result) => {
        if (result.success) {
            (0, NotificationCenter_1.showNotification)(nodePathInfos.length === 1
                ? 'Removed sequence from source file'
                : 'Removed sequences from source files', 2000);
        }
        else {
            (0, NotificationCenter_1.showNotification)(result.reason, 4000);
        }
        return true;
    })
        .catch((err) => {
        (0, NotificationCenter_1.showNotification)(err.message, 4000);
        return true;
    });
};
const deleteEffects = (effects) => {
    if (effects.length === 0) {
        return Promise.resolve(false);
    }
    return (0, call_api_1.callApi)('/api/delete-effect', effects.map((effect) => {
        const nodePath = effect.nodePathInfo.sequenceSubscriptionKey;
        return effect.type === 'single-effect'
            ? {
                type: 'single-effect',
                fileName: nodePath.absolutePath,
                sequenceNodePath: nodePath,
                effectIndex: effect.effectIndex,
            }
            : {
                type: 'all-effects',
                fileName: nodePath.absolutePath,
                sequenceNodePath: nodePath,
            };
    }))
        .then((result) => {
        if (result.success) {
            const singleEffect = effects[0];
            (0, NotificationCenter_1.showNotification)(effects.length === 1 && (singleEffect === null || singleEffect === void 0 ? void 0 : singleEffect.type) === 'single-effect'
                ? 'Removed effect from source file'
                : effects.length === 1
                    ? 'Removed effects from source file'
                    : 'Removed effects from source files', 2000);
            return true;
        }
        (0, NotificationCenter_1.showNotification)(result.reason, 4000);
        return false;
    })
        .catch((err) => {
        (0, NotificationCenter_1.showNotification)(err.message, 4000);
        return false;
    });
};
const deleteSelectedTimelineItem = ({ selection, sequences, overrideIdsToNodePaths, setPropStatuses, clientId, confirm, }) => {
    var _a;
    if (selection.type === 'keyframe') {
        const promise = (0, delete_selected_keyframe_1.deleteSelectedKeyframe)({
            nodePathInfo: selection.nodePathInfo,
            frame: selection.frame,
            sequences,
            overrideIdsToNodePaths,
            setPropStatuses,
            clientId,
        });
        return (_a = promise === null || promise === void 0 ? void 0 : promise.then(() => true)) !== null && _a !== void 0 ? _a : null;
    }
    switch (selection.type) {
        case 'guide':
            return null;
        case 'sequence':
            return deleteSequences([selection.nodePathInfo], confirm);
        case 'sequence-effect':
            return deleteEffects([
                {
                    type: 'single-effect',
                    nodePathInfo: selection.nodePathInfo,
                    effectIndex: selection.i,
                },
            ]);
        case 'sequence-prop':
        case 'sequence-effect-prop':
        case 'easing':
            return null;
        case 'sequence-all-effects':
            return deleteEffects([
                { type: 'all-effects', nodePathInfo: selection.nodePathInfo },
            ]);
        default:
            throw new Error(`Unexpected timeline selection type: ${selection}`);
    }
};
exports.deleteSelectedTimelineItem = deleteSelectedTimelineItem;
const isSequenceRowSelection = (selection) => selection.type === 'sequence';
const isSequenceEffectSelection = (selection) => selection.type === 'sequence-effect';
const isSequenceAllEffectsSelection = (selection) => selection.type === 'sequence-all-effects';
const isKeyframeSelection = (selection) => selection.type === 'keyframe';
const getSequenceSelectionAfterDeletingEffect = (selection) => {
    if (selection.type !== 'sequence-effect' &&
        selection.type !== 'sequence-all-effects') {
        return null;
    }
    return {
        type: 'sequence',
        nodePathInfo: {
            ...selection.nodePathInfo,
            auxiliaryKeys: [],
        },
    };
};
const getEasingSelectionAfterDeletingKeyframes = ({ selections, sequences, overrideIdsToNodePaths, propStatuses, timelinePosition, }) => {
    var _a;
    if (sequences === undefined ||
        overrideIdsToNodePaths === undefined ||
        propStatuses === undefined ||
        timelinePosition === undefined) {
        return null;
    }
    const keyframeSelections = selections.filter(isKeyframeSelection);
    if (keyframeSelections.length !== 1) {
        return null;
    }
    const [selection] = keyframeSelections;
    if (!selection) {
        return null;
    }
    const field = (0, parse_keyframe_field_from_node_path_1.parseKeyframeFieldFromNodePath)(selection.nodePathInfo.auxiliaryKeys);
    if (field === null) {
        return null;
    }
    const track = (0, find_track_for_node_path_info_1.findTrackForNodePathInfo)({
        sequences,
        overrideIdsToNodePaths,
        nodePathInfo: selection.nodePathInfo,
    });
    if (!track || !track.sequence.controls) {
        return null;
    }
    const nodePath = selection.nodePathInfo.sequenceSubscriptionKey;
    const sourceFrame = selection.frame - track.keyframeDisplayOffset;
    if (field.type === 'sequence') {
        const sequencePropStatus = (_a = remotion_1.Internals.getPropStatusesCtx(propStatuses, nodePath)) === null || _a === void 0 ? void 0 : _a[field.fieldKey];
        if ((sequencePropStatus === null || sequencePropStatus === void 0 ? void 0 : sequencePropStatus.status) !== 'keyframed' ||
            !(0, update_selected_easing_1.canEditEasingForInterpolationFunction)(sequencePropStatus.interpolationFunction)) {
            return null;
        }
        return (0, get_easing_selection_after_keyframe_delete_1.getEasingSelectionAfterKeyframeDelete)({
            deletedSourceFrames: [sourceFrame],
            keyframeDisplayOffset: track.keyframeDisplayOffset,
            nodePathInfo: selection.nodePathInfo,
            propStatus: sequencePropStatus,
            timelinePosition,
        });
    }
    const effectStatus = remotion_1.Internals.getEffectPropStatusesCtx({
        propStatuses,
        nodePath,
        effectIndex: field.effectIndex,
    });
    const effectPropStatus = effectStatus.type === 'can-update-effect'
        ? effectStatus.props[field.fieldKey]
        : null;
    if ((effectPropStatus === null || effectPropStatus === void 0 ? void 0 : effectPropStatus.status) !== 'keyframed' ||
        !(0, update_selected_easing_1.canEditEasingForInterpolationFunction)(effectPropStatus.interpolationFunction)) {
        return null;
    }
    return (0, get_easing_selection_after_keyframe_delete_1.getEasingSelectionAfterKeyframeDelete)({
        deletedSourceFrames: [sourceFrame],
        keyframeDisplayOffset: track.keyframeDisplayOffset,
        nodePathInfo: selection.nodePathInfo,
        propStatus: effectPropStatus,
        timelinePosition,
    });
};
const getTimelineSelectionAfterDeletingItems = ({ selections, sequences, overrideIdsToNodePaths, propStatuses, timelinePosition, }) => {
    const easingSelection = getEasingSelectionAfterDeletingKeyframes({
        selections,
        sequences,
        overrideIdsToNodePaths,
        propStatuses,
        timelinePosition,
    });
    if (easingSelection !== null) {
        return [easingSelection];
    }
    const nextSelections = new Map();
    for (const selection of selections) {
        const nextSelection = getSequenceSelectionAfterDeletingEffect(selection);
        if (!nextSelection) {
            return [];
        }
        nextSelections.set((0, TimelineSelection_1.getTimelineSelectionKey)(nextSelection), nextSelection);
    }
    return Array.from(nextSelections.values());
};
exports.getTimelineSelectionAfterDeletingItems = getTimelineSelectionAfterDeletingItems;
const areSelectionsOnlyOfType = (selections, type) => selections.every((selection) => selection.type === type);
const assertTimelineSelectionsHaveSameType = (selections) => {
    const firstSelection = selections[0];
    if (!firstSelection) {
        return;
    }
    for (const selection of selections) {
        if (selection.type !== firstSelection.type) {
            throw new Error(`Assertion failed: Cannot delete timeline selections of different types (${firstSelection.type}, ${selection.type})`);
        }
    }
};
const containsOnlyKeyframesAndEasings = (selections) => selections.every((selection) => selection.type === 'keyframe' || selection.type === 'easing');
const deleteSelectedTimelineItems = ({ selections, sequences, overrideIdsToNodePaths, setPropStatuses, clientId, confirm, }) => {
    var _a;
    const firstSelection = selections[0];
    if (!firstSelection) {
        return null;
    }
    if (containsOnlyKeyframesAndEasings(selections)) {
        const keyframes = selections.filter(isKeyframeSelection);
        if (keyframes.length === 0) {
            return null;
        }
        const promise = (0, delete_selected_keyframe_1.deleteSelectedKeyframes)({
            keyframes: keyframes.map((selection) => ({
                nodePathInfo: selection.nodePathInfo,
                frame: selection.frame,
            })),
            sequences,
            overrideIdsToNodePaths,
            setPropStatuses,
            clientId,
        });
        return (_a = promise === null || promise === void 0 ? void 0 : promise.then(() => true)) !== null && _a !== void 0 ? _a : null;
    }
    if (!areSelectionsOnlyOfType(selections, firstSelection.type)) {
        return null;
    }
    assertTimelineSelectionsHaveSameType(selections);
    switch (firstSelection.type) {
        case 'guide':
            return null;
        case 'sequence':
            return deleteSequences(selections
                .filter(isSequenceRowSelection)
                .map((selection) => selection.nodePathInfo), confirm);
        case 'sequence-effect':
            return deleteEffects(selections.filter(isSequenceEffectSelection).map((selection) => ({
                type: 'single-effect',
                nodePathInfo: selection.nodePathInfo,
                effectIndex: selection.i,
            })));
        case 'keyframe':
        case 'sequence-prop':
        case 'sequence-effect-prop':
        case 'easing':
            return null;
        case 'sequence-all-effects':
            return deleteEffects(selections.filter(isSequenceAllEffectsSelection).map((selection) => ({
                type: 'all-effects',
                nodePathInfo: selection.nodePathInfo,
            })));
        default:
            throw new Error(`Unexpected timeline selection type: ${firstSelection}`);
    }
};
exports.deleteSelectedTimelineItems = deleteSelectedTimelineItems;
