import { logger } from "../../logging/GlobalLogger.js";
import { AnimationCurve } from "../curve/AnimationCurve.js";
import { AnimationClip } from "./AnimationClip.js";
import { AnimationClipBinding } from "./AnimationClipBinding.js";
import { AnimationInterpolationKind } from "./AnimationInterpolationKind.js";
import { AnimationTrack } from "./AnimationTrack.js";
import { AnimationTrackBinding } from "./AnimationTrackBinding.js";
import { bind_property_writer } from "./bind_property_writer.js";
import { curve_from_track_data } from "./curve_from_track_data.js";


/**
 *
 * @param {THREE.KeyframeTrack} track
 */
function track_to_interpolation(track) {
    const name = track.createInterpolant.name;

    switch (name) {
        case "InterpolantFactoryMethodDiscrete":
            return AnimationInterpolationKind.Discrete;
        case "InterpolantFactoryMethodLinear":
            return AnimationInterpolationKind.Linear;
        case "InterpolantFactoryMethodGLTFCubicSpline":
            return AnimationInterpolationKind.CubicTangents;

        default:

            if (track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline === true) {
                // second attempt
                return AnimationInterpolationKind.CubicTangents;
            }

            // unsupported, default to linear
            console.warn(`Unsupported interpolation type, defaulting to linear`);
            return AnimationInterpolationKind.Linear;
    }
}

/**
 *
 * @param {THREE.KeyframeTrack} track
 * @returns {AnimationCurve[]}
 */
function convert_three_track_to_curves(track) {

    const values = track.values;
    const times = track.times;

    const key_count = times.length;

    /**
     *
     * @type {AnimationCurve[]}
     */
    const curves = [];

    // figure out interpolation type
    const interpolation = track_to_interpolation(track);

    const values_per_key = values.length / key_count;

    const component_count = interpolation === AnimationInterpolationKind.CubicTangents ? values_per_key / 3 : values_per_key;

    for (let component_index = 0; component_index < component_count; component_index++) {

        const curve = new AnimationCurve();

        curve_from_track_data(
            curve,
            interpolation,
            values,
            times,
            component_count,
            component_index
        );

        curves.push(curve);

    }
    return curves;
}


/**
 *
 * @param {THREE.KeyframeTrack} track
 * @returns {AnimationTrack}
 */
function convert_three_track(track) {

    const track_name = track.name;

    // last part is the property
    const curves = convert_three_track_to_curves(track);

    return AnimationTrack.from(curves, track_name);

}

/**
 * Three.js clip to internal representation
 * @param {EntityNode} node
 * @param {THREE.AnimationClip} clip
 */
export function convert_three_clip(node, clip) {
    const three_tracks = clip.tracks;
    const track_count = three_tracks.length;


    const clip_binding = new AnimationClipBinding();
    const meep_clip = new AnimationClip();

    meep_clip.name = clip.name;

    clip_binding.clip = meep_clip;

    for (let i = 0; i < track_count; i++) {
        try {
            const three_track = three_tracks[i];

            const meep_track = convert_three_track(three_track);

            const property_path = three_track.name.split('.');

            const writer = bind_property_writer(node, property_path);

            meep_clip.tracks.push(meep_track);
            clip_binding.tracks.push(AnimationTrackBinding.from(writer, meep_track));
        } catch (e) {
            logger.error(`Failed to parse track[${i}]: ${e}`);
        }
    }

    return clip_binding;
}