"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getPasteKeyframeTarget = exports.getKeyframeClipboardDataFromSelections = void 0;
const studio_shared_1 = require("@remotion/studio-shared");
const remotion_1 = require("remotion");
const find_track_for_node_path_info_1 = require("./find-track-for-node-path-info");
const parse_keyframe_field_from_node_path_1 = require("./parse-keyframe-field-from-node-path");
const getKeyframeClipboardFieldType = ({ schema, fieldKey, }) => {
    const field = remotion_1.Internals.getFlatSchemaWithAllKeys(schema)[fieldKey];
    if (!field) {
        return null;
    }
    return (0, studio_shared_1.isKeyframeClipboardFieldType)(field.type) ? field.type : null;
};
const getKeyframeFieldIdentity = (selection) => {
    if (selection.type === 'keyframe' || selection.type === 'easing') {
        return (0, parse_keyframe_field_from_node_path_1.parseKeyframeFieldFromNodePath)(selection.nodePathInfo.auxiliaryKeys);
    }
    if (selection.type === 'sequence-prop') {
        return { type: 'sequence', fieldKey: selection.key };
    }
    if (selection.type === 'sequence-effect-prop') {
        return {
            type: 'effect',
            effectIndex: selection.i,
            fieldKey: selection.key,
        };
    }
    return null;
};
const resolveKeyframeField = ({ selection, sequences, overrideIdsToNodePaths, propStatuses, }) => {
    var _a, _b;
    if (selection.type !== 'keyframe' &&
        selection.type !== 'easing' &&
        selection.type !== 'sequence-prop' &&
        selection.type !== 'sequence-effect-prop') {
        return null;
    }
    const identity = getKeyframeFieldIdentity(selection);
    if (identity === null) {
        return null;
    }
    const track = (0, find_track_for_node_path_info_1.findTrackForNodePathInfo)({
        sequences,
        overrideIdsToNodePaths,
        nodePathInfo: selection.nodePathInfo,
    });
    if (!track || track.nodePathInfo === null) {
        return null;
    }
    const nodePath = track.nodePathInfo.sequenceSubscriptionKey;
    if (identity.type === 'sequence') {
        if (!track.sequence.controls) {
            return null;
        }
        const sequencePropStatus = (_a = remotion_1.Internals.getPropStatusesCtx(propStatuses, nodePath)) === null || _a === void 0 ? void 0 : _a[identity.fieldKey];
        if (!sequencePropStatus || sequencePropStatus.status === 'computed') {
            return null;
        }
        const { schema } = track.sequence.controls;
        return {
            identity,
            nodePath,
            fileName: nodePath.absolutePath,
            schema,
            fieldType: getKeyframeClipboardFieldType({
                schema,
                fieldKey: identity.fieldKey,
            }),
            propStatus: sequencePropStatus,
            keyframeDisplayOffset: track.keyframeDisplayOffset,
        };
    }
    const effect = track.sequence.effects[identity.effectIndex];
    const effectStatus = remotion_1.Internals.getEffectPropStatusesCtx({
        propStatuses,
        nodePath,
        effectIndex: identity.effectIndex,
    });
    const effectPropStatus = effectStatus.type === 'can-update-effect'
        ? (_b = effectStatus.props) === null || _b === void 0 ? void 0 : _b[identity.fieldKey]
        : null;
    if (!effect || !effectPropStatus || effectPropStatus.status === 'computed') {
        return null;
    }
    return {
        identity,
        nodePath,
        fileName: nodePath.absolutePath,
        schema: effect.schema,
        fieldType: getKeyframeClipboardFieldType({
            schema: effect.schema,
            fieldKey: identity.fieldKey,
        }),
        propStatus: effectPropStatus,
        keyframeDisplayOffset: track.keyframeDisplayOffset,
    };
};
const areResolvedFieldsEqual = (first, second) => {
    if (remotion_1.Internals.makeSequencePropsSubscriptionKey(first.nodePath) !==
        remotion_1.Internals.makeSequencePropsSubscriptionKey(second.nodePath)) {
        return false;
    }
    if (first.identity.type !== second.identity.type) {
        return false;
    }
    if (first.identity.fieldKey !== second.identity.fieldKey) {
        return false;
    }
    return (first.identity.type === 'sequence' ||
        (second.identity.type === 'effect' &&
            first.identity.effectIndex === second.identity.effectIndex));
};
const getKeyframeClipboardDataFromSelections = ({ selections, sequences, overrideIdsToNodePaths, propStatuses, }) => {
    var _a, _b;
    const keyframeSelections = selections.filter((selection) => selection.type === 'keyframe');
    const easingSelections = selections.filter((selection) => selection.type === 'easing');
    if (keyframeSelections.length + easingSelections.length !==
        selections.length) {
        return null;
    }
    const resolvedFields = keyframeSelections.map((selection) => ({
        selection,
        resolved: resolveKeyframeField({
            selection,
            sequences,
            overrideIdsToNodePaths,
            propStatuses,
        }),
    }));
    const firstResolved = (_a = resolvedFields[0]) === null || _a === void 0 ? void 0 : _a.resolved;
    if (firstResolved === null ||
        firstResolved === undefined ||
        resolvedFields.some(({ resolved }) => resolved === null || !areResolvedFieldsEqual(firstResolved, resolved))) {
        return null;
    }
    const keyframedPropStatus = firstResolved.propStatus;
    if (keyframedPropStatus.status !== 'keyframed') {
        return null;
    }
    const keyframes = [];
    for (const { selection } of resolvedFields) {
        const sourceFrame = selection.frame - firstResolved.keyframeDisplayOffset;
        const keyframe = keyframedPropStatus.keyframes.find((item) => item.frame === sourceFrame);
        if (keyframe === undefined ||
            JSON.stringify(keyframe.value) === undefined) {
            return null;
        }
        keyframes.push({ frame: sourceFrame, value: keyframe.value });
    }
    keyframes.sort((first, second) => first.frame - second.frame);
    const firstFrame = (_b = keyframes[0]) === null || _b === void 0 ? void 0 : _b.frame;
    if (firstFrame === undefined) {
        return null;
    }
    const keyframeIndexes = keyframes.map((keyframe) => keyframedPropStatus.keyframes.findIndex((item) => item.frame === keyframe.frame));
    if (keyframeIndexes.some((index, position) => index === -1 ||
        (position > 0 && index !== keyframeIndexes[position - 1] + 1))) {
        return null;
    }
    const firstKeyframeIndex = keyframeIndexes[0];
    const lastKeyframeIndex = keyframeIndexes.at(-1);
    if (firstKeyframeIndex === undefined || lastKeyframeIndex === undefined) {
        return null;
    }
    for (const easingSelection of easingSelections) {
        const resolved = resolveKeyframeField({
            selection: easingSelection,
            sequences,
            overrideIdsToNodePaths,
            propStatuses,
        });
        if (resolved === null ||
            !areResolvedFieldsEqual(firstResolved, resolved) ||
            easingSelection.segmentIndex < firstKeyframeIndex ||
            easingSelection.segmentIndex >= lastKeyframeIndex) {
            return null;
        }
    }
    return {
        type: 'keyframe',
        version: 1,
        remotionClipboard: 'keyframe',
        fieldType: firstResolved.fieldType,
        keyframes: keyframes.map((keyframe) => {
            return {
                frameOffset: keyframe.frame - firstFrame,
                value: keyframe.value,
            };
        }),
        easing: keyframeIndexes.slice(0, -1).map((index) => {
            var _a;
            return (_a = keyframedPropStatus.easing[index]) !== null && _a !== void 0 ? _a : studio_shared_1.LINEAR_KEYFRAME_EASING;
        }),
    };
};
exports.getKeyframeClipboardDataFromSelections = getKeyframeClipboardDataFromSelections;
const isKeyframeValueCompatible = ({ value, fieldType, }) => {
    if (fieldType === null) {
        return true;
    }
    if (fieldType === 'number' || fieldType === 'rotation-degrees') {
        return typeof value === 'number' && Number.isFinite(value);
    }
    if (fieldType === 'scale') {
        return ((typeof value === 'number' && Number.isFinite(value)) ||
            typeof value === 'string');
    }
    if (fieldType === 'uv-coordinate') {
        return (Array.isArray(value) &&
            value.length === 2 &&
            value.every((item) => typeof item === 'number' && Number.isFinite(item)));
    }
    return typeof value === 'string';
};
const getPasteKeyframeTarget = ({ selectedItems, payload, timelinePosition, sequences, overrideIdsToNodePaths, propStatuses, }) => {
    var _a, _b;
    if (selectedItems.length === 0) {
        return { type: 'none' };
    }
    const selection = selectedItems[0];
    if (!selection || getKeyframeFieldIdentity(selection) === null) {
        return { type: 'none' };
    }
    const resolvedFields = selectedItems.map((item) => resolveKeyframeField({
        selection: item,
        sequences,
        overrideIdsToNodePaths,
        propStatuses,
    }));
    const resolved = resolvedFields[0];
    if (resolved === null) {
        return { type: 'uncopyable' };
    }
    if (resolvedFields.some((field) => field === null || !areResolvedFieldsEqual(resolved, field))) {
        return { type: 'multiple' };
    }
    const keyframes = payload.keyframes.map((keyframe) => ({
        sourceFrame: timelinePosition - resolved.keyframeDisplayOffset + keyframe.frameOffset,
        value: keyframe.value,
    }));
    const firstFrame = (_a = keyframes[0]) === null || _a === void 0 ? void 0 : _a.sourceFrame;
    const lastFrame = (_b = keyframes.at(-1)) === null || _b === void 0 ? void 0 : _b.sourceFrame;
    if (firstFrame === undefined || lastFrame === undefined) {
        return { type: 'incompatible' };
    }
    const existingFrames = resolved.propStatus.status === 'keyframed'
        ? resolved.propStatus.keyframes.map((keyframe) => keyframe.frame)
        : [];
    const keyframesToDelete = existingFrames.filter((frame) => frame >= firstFrame && frame <= lastFrame);
    const finalFrames = [
        ...existingFrames.filter((frame) => frame < firstFrame || frame > lastFrame),
        ...keyframes.map((keyframe) => keyframe.sourceFrame),
    ].sort((first, second) => first - second);
    const firstEasingSegmentIndex = finalFrames.indexOf(firstFrame);
    if (resolved.fieldType !== payload.fieldType ||
        payload.keyframes.some((keyframe) => !isKeyframeValueCompatible({
            value: keyframe.value,
            fieldType: payload.fieldType,
        }))) {
        return { type: 'incompatible' };
    }
    return {
        type: 'valid',
        fileName: resolved.fileName,
        nodePath: resolved.nodePath,
        fieldKey: resolved.identity.fieldKey,
        effectIndex: resolved.identity.type === 'effect'
            ? resolved.identity.effectIndex
            : null,
        keyframes,
        keyframesToDelete,
        easing: payload.easing,
        firstEasingSegmentIndex,
        schema: resolved.schema,
    };
};
exports.getPasteKeyframeTarget = getPasteKeyframeTarget;
