"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TimelineSequencePropItem = exports.TimelineSequenceKeyframedValue = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const studio_shared_1 = require("@remotion/studio-shared");
const react_1 = require("react");
const remotion_1 = require("remotion");
const client_id_1 = require("../../helpers/client-id");
const ContextMenu_1 = require("../ContextMenu");
const call_add_keyframe_1 = require("./call-add-keyframe");
const get_animation_item_selection_for_frame_1 = require("./get-animation-item-selection-for-frame");
const save_sequence_prop_1 = require("./save-sequence-prop");
const TimelineExpandArrowButton_1 = require("./TimelineExpandArrowButton");
const TimelineFieldRowContent_1 = require("./TimelineFieldRowContent");
const TimelineKeyframeControls_1 = require("./TimelineKeyframeControls");
const TimelineKeyframedValue_1 = require("./TimelineKeyframedValue");
const TimelineLayerEye_1 = require("./TimelineLayerEye");
const TimelineRowChrome_1 = require("./TimelineRowChrome");
const TimelineSchemaField_1 = require("./TimelineSchemaField");
const TimelineSelection_1 = require("./TimelineSelection");
const update_selected_easing_1 = require("./update-selected-easing");
const fieldRowBase = {};
const isKeyframedStatus = (status) => {
    return status.status === 'keyframed';
};
const isResettableStatus = ({ status, defaultValue, }) => {
    var _a;
    if (defaultValue === undefined) {
        return false;
    }
    if (status.status === 'keyframed') {
        return true;
    }
    if (status.status === 'computed') {
        return false;
    }
    const effectiveCodeValue = (_a = status.codeValue) !== null && _a !== void 0 ? _a : defaultValue;
    return JSON.stringify(effectiveCodeValue) !== JSON.stringify(defaultValue);
};
const Value = ({ field, nodePath, validatedLocation, schema, propStatus }) => {
    const { getDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeDragOverridesContext);
    const { setDragOverrides, clearDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
    const dragOverrideValue = (0, react_1.useMemo)(() => {
        var _a;
        return nodePath === null
            ? undefined
            : ((_a = getDragOverrides(nodePath)) !== null && _a !== void 0 ? _a : {})[field.key];
    }, [getDragOverrides, nodePath, field.key]);
    const effectiveValue = remotion_1.Internals.getEffectiveVisualModeValue({
        propStatus,
        dragOverrideValue,
        defaultValue: field.fieldSchema.default,
        shouldResortToDefaultValueIfUndefined: true,
    });
    const { setPropStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
    const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
    const clientId = previewServerState.type === 'connected'
        ? previewServerState.clientId
        : null;
    const onSave = (0, react_1.useCallback)((value, options) => {
        var _a;
        if (!clientId) {
            return Promise.reject(new Error('Not connected to studio server'));
        }
        const defaultValue = field.fieldSchema.type === 'text-content'
            ? null
            : field.fieldSchema.default !== undefined
                ? JSON.stringify(field.fieldSchema.default)
                : null;
        const stringifiedValue = JSON.stringify(value);
        const fieldLabel = (_a = field.description) !== null && _a !== void 0 ? _a : field.key;
        if (value === propStatus.codeValue) {
            return Promise.resolve();
        }
        if (defaultValue === stringifiedValue &&
            propStatus.codeValue === undefined) {
            return Promise.resolve();
        }
        return (0, save_sequence_prop_1.saveSequenceProps)({
            changes: [
                {
                    fileName: validatedLocation.source,
                    nodePath,
                    fieldKey: field.key,
                    value,
                    defaultValue,
                    schema,
                    sourceEdit: options === null || options === void 0 ? void 0 : options.sourceEdit,
                },
            ],
            setPropStatuses,
            clientId,
            undoLabel: `Update ${fieldLabel}`,
            redoLabel: `Update ${fieldLabel} again`,
        });
    }, [
        propStatus,
        clientId,
        field.description,
        field.fieldSchema.default,
        field.fieldSchema.type,
        field.key,
        nodePath,
        schema,
        setPropStatuses,
        validatedLocation,
    ]);
    const onDragValueChange = (0, react_1.useCallback)((value) => {
        if (nodePath === null) {
            throw new Error('Cannot drag value');
        }
        setDragOverrides(nodePath, field.key, remotion_1.Internals.makeStaticDragOverride(value));
    }, [setDragOverrides, nodePath, field.key]);
    const onDragEnd = (0, react_1.useCallback)(() => {
        if (nodePath === null) {
            throw new Error('Cannot clear drag value');
        }
        clearDragOverrides(nodePath);
    }, [clearDragOverrides, nodePath]);
    return (jsx_runtime_1.jsx(TimelineSchemaField_1.TimelineFieldValue, { field: field, propStatus: propStatus, onSave: onSave, onDragValueChange: onDragValueChange, onDragEnd: onDragEnd, effectiveValue: effectiveValue, scaleLockNodePath: nodePath }));
};
const TimelineSequenceKeyframedValue = ({ field, fileName, nodePath, schema, propStatus, sourceFrame }) => {
    const { getDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeDragOverridesContext);
    const { setPropStatuses, setDragOverrides, clearDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
    const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
    const clientId = previewServerState.type === 'connected'
        ? previewServerState.clientId
        : null;
    const dragOverrideValue = (0, react_1.useMemo)(() => {
        var _a;
        return ((_a = getDragOverrides(nodePath)) !== null && _a !== void 0 ? _a : {})[field.key];
    }, [getDragOverrides, nodePath, field.key]);
    const onSaveKeyframed = (0, react_1.useCallback)((value, frame) => {
        if (!clientId) {
            return Promise.reject(new Error('Not connected to studio server'));
        }
        return (0, call_add_keyframe_1.callAddSequenceKeyframe)({
            fileName,
            nodePath,
            fieldKey: field.key,
            sourceFrame: frame,
            value,
            schema,
            setPropStatuses,
            clientId,
        });
    }, [clientId, field.key, fileName, nodePath, schema, setPropStatuses]);
    const onKeyframedDragValueChange = (0, react_1.useCallback)((value) => {
        setDragOverrides(nodePath, field.key, remotion_1.Internals.makeKeyframedDragOverride({
            status: propStatus,
            frame: sourceFrame,
            value,
        }));
    }, [propStatus, field.key, nodePath, setDragOverrides, sourceFrame]);
    const onKeyframedDragEnd = (0, react_1.useCallback)(() => {
        clearDragOverrides(nodePath);
    }, [clearDragOverrides, nodePath]);
    return (jsx_runtime_1.jsx(TimelineKeyframedValue_1.TimelineKeyframedValue, { field: field, propStatus: propStatus, sourceFrame: sourceFrame, dragOverrideValue: dragOverrideValue, onSave: onSaveKeyframed, onDragValueChange: onKeyframedDragValueChange, onDragEnd: onKeyframedDragEnd, scaleLockNodePath: nodePath }));
};
exports.TimelineSequenceKeyframedValue = TimelineSequenceKeyframedValue;
const TimelineSequencePropItem = ({ field, validatedLocation, rowDepth, nodePath, nodePathInfo, schema, keyframeDisplayOffset, keyframeControlsMode = 'timeline', }) => {
    var _a;
    const { propStatuses: visualModePropStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesContext);
    const { getDragOverrides } = (0, react_1.useContext)(remotion_1.Internals.VisualModeDragOverridesContext);
    const { setPropStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
    const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
    const selection = (0, TimelineSelection_1.useTimelineRowSelection)(nodePathInfo);
    const { selectItems } = (0, TimelineSelection_1.useTimelineSelection)();
    const setFrame = remotion_1.Internals.useTimelineSetFrame();
    const videoConfig = (0, remotion_1.useVideoConfig)();
    const timelinePosition = remotion_1.Internals.Timeline.useTimelinePosition();
    const sourceFrame = timelinePosition - keyframeDisplayOffset;
    const propStatusesForOverride = remotion_1.Internals.getPropStatusesCtx(visualModePropStatuses, nodePath);
    const propStatus = (_a = propStatusesForOverride === null || propStatusesForOverride === void 0 ? void 0 : propStatusesForOverride[field.key]) !== null && _a !== void 0 ? _a : null;
    const dragOverrideValue = (0, react_1.useMemo)(() => {
        var _a;
        return ((_a = getDragOverrides(nodePath)) !== null && _a !== void 0 ? _a : {})[field.key];
    }, [getDragOverrides, nodePath, field.key]);
    const keyframable = (0, studio_shared_1.isSchemaFieldKeyframable)({
        schema,
        key: field.key,
    });
    const keyframeControls = propStatus !== null &&
        (keyframeControlsMode === 'inspector'
            ? keyframable
            : (0, TimelineKeyframeControls_1.shouldShowTimelineKeyframeControls)({
                propStatus,
                selected: selection.selected,
                keyframable,
            })) ? (jsx_runtime_1.jsx(TimelineKeyframeControls_1.TimelineKeyframeControls, { fieldKey: field.key, propStatus: propStatus, nodePath: nodePath, fileName: validatedLocation.source, keyframeDisplayOffset: keyframeDisplayOffset, defaultValue: field.fieldSchema.default, dragOverrideValue: dragOverrideValue, schema: schema, effectIndex: null, nodePathInfo: nodePathInfo, mode: keyframeControlsMode })) : null;
    const style = (0, react_1.useMemo)(() => {
        return field.typeName === 'text-content'
            ? fieldRowBase
            : { ...fieldRowBase, height: field.rowHeight };
    }, [field.rowHeight, field.typeName]);
    const canResetToDefault = (0, react_1.useMemo)(() => {
        if (!propStatus || propStatus.status === 'computed') {
            return false;
        }
        return isResettableStatus({
            status: propStatus,
            defaultValue: field.fieldSchema.default,
        });
    }, [propStatus, field.fieldSchema.default]);
    const canPerformReset = previewServerState.type === 'connected' &&
        propStatus !== null &&
        propStatus.status !== 'computed';
    const canShowReset = canPerformReset && field.fieldSchema.default !== undefined;
    const onReset = (0, react_1.useCallback)(() => {
        var _a;
        if (!canShowReset ||
            !canResetToDefault ||
            previewServerState.type !== 'connected' ||
            propStatus === null) {
            return;
        }
        const defaultValue = field.fieldSchema.default !== undefined
            ? JSON.stringify(field.fieldSchema.default)
            : null;
        const fieldLabel = (_a = field.description) !== null && _a !== void 0 ? _a : field.key;
        (0, save_sequence_prop_1.saveSequenceProps)({
            changes: [
                {
                    fileName: validatedLocation.source,
                    nodePath,
                    fieldKey: field.key,
                    value: field.fieldSchema.default,
                    defaultValue,
                    schema,
                },
            ],
            setPropStatuses,
            clientId: previewServerState.clientId,
            undoLabel: `Reset ${fieldLabel}`,
            redoLabel: `Reapply ${fieldLabel}`,
        });
    }, [
        canResetToDefault,
        canShowReset,
        field.description,
        field.fieldSchema.default,
        field.key,
        nodePath,
        previewServerState,
        schema,
        setPropStatuses,
        validatedLocation.source,
        propStatus,
    ]);
    const contextMenuValues = (0, react_1.useMemo)(() => {
        return [
            {
                type: 'item',
                id: 'reset-sequence-field',
                keyHint: null,
                label: 'Reset',
                leftItem: null,
                disabled: !canShowReset,
                onClick: onReset,
                quickSwitcherLabel: null,
                subMenu: null,
                value: 'reset-sequence-field',
            },
        ];
    }, [canShowReset, onReset]);
    const seekToDisplayFrame = (0, react_1.useCallback)((frame) => {
        setFrame((current) => {
            const next = { ...current, [videoConfig.id]: frame };
            remotion_1.Internals.persistCurrentFrame(next);
            return next;
        });
    }, [setFrame, videoConfig.id]);
    const onPropertyDoubleClick = (0, react_1.useCallback)((event) => {
        if (propStatus === null || propStatus.status === 'computed') {
            return;
        }
        const keyframeSelection = {
            type: 'keyframe',
            nodePathInfo,
            frame: sourceFrame + keyframeDisplayOffset,
        };
        if (propStatus.status === 'static') {
            if (!keyframable || previewServerState.type !== 'connected') {
                return;
            }
            const value = remotion_1.Internals.getEffectiveVisualModeValue({
                propStatus,
                dragOverrideValue,
                frame: sourceFrame,
                defaultValue: field.fieldSchema.default,
                shouldResortToDefaultValueIfUndefined: true,
            });
            event.stopPropagation();
            (0, call_add_keyframe_1.callAddSequenceKeyframe)({
                fileName: validatedLocation.source,
                nodePath,
                fieldKey: field.key,
                sourceFrame,
                value,
                schema,
                setPropStatuses,
                clientId: previewServerState.clientId,
            }).catch(() => undefined);
            selectItems([keyframeSelection], { reveal: true });
            seekToDisplayFrame(keyframeSelection.frame);
            return;
        }
        const targetSelection = (0, get_animation_item_selection_for_frame_1.getAnimationItemSelectionForSourceFrame)({
            includeEasings: (0, update_selected_easing_1.canEditEasingForInterpolationFunction)(propStatus.interpolationFunction),
            keyframeDisplayOffset,
            keyframes: propStatus.keyframes,
            nodePathInfo,
            sourceFrame,
        });
        if (targetSelection === null) {
            return;
        }
        event.stopPropagation();
        selectItems([targetSelection], { reveal: true });
        if (targetSelection.type === 'keyframe') {
            seekToDisplayFrame(targetSelection.frame);
        }
    }, [
        dragOverrideValue,
        field.fieldSchema.default,
        field.key,
        keyframeDisplayOffset,
        keyframable,
        nodePath,
        nodePathInfo,
        previewServerState,
        propStatus,
        schema,
        seekToDisplayFrame,
        selectItems,
        setPropStatuses,
        sourceFrame,
        validatedLocation.source,
    ]);
    if (propStatus === null) {
        return null;
    }
    const fieldValue = isKeyframedStatus(propStatus) ? (jsx_runtime_1.jsx(exports.TimelineSequenceKeyframedValue, { field: field, fileName: validatedLocation.source, nodePath: nodePath, schema: schema, propStatus: propStatus, sourceFrame: sourceFrame })) : propStatus.status === 'static' ? (jsx_runtime_1.jsx(Value, { field: field, nodePath: nodePath, validatedLocation: validatedLocation, schema: schema, propStatus: propStatus })) : (jsx_runtime_1.jsx(TimelineSchemaField_1.TimelineNonEditableStatus, { propStatus: propStatus }));
    const row = (jsx_runtime_1.jsx(TimelineRowChrome_1.TimelineRowChrome, { depth: rowDepth, eye: jsx_runtime_1.jsx(TimelineLayerEye_1.TimelineLayerEyeSpacer, {}), keyframeControls: keyframeControls, arrow: jsx_runtime_1.jsx(TimelineExpandArrowButton_1.TimelineExpandArrowSpacer, {}), style: style, selected: selection.selected, selectable: selection.selectable, selectionItem: selection.selectionItem, onSelect: selection.onSelect, onDoubleClick: onPropertyDoubleClick, showSelectedBackground: true, containsSelection: false, outerHeight: null, children: jsx_runtime_1.jsx(TimelineFieldRowContent_1.TimelineFieldRowContent, { field: field, rowDepth: rowDepth, selected: selection.selected, children: fieldValue }) }));
    return (jsx_runtime_1.jsx(ContextMenu_1.ContextMenu, { values: contextMenuValues, onOpen: selection.selectable ? selection.onSelect : null, children: row }));
};
exports.TimelineSequencePropItem = TimelineSequencePropItem;
