export class AnimationMotionQualityTracker {
    maxSamples;
    minimumSamples;
    minimumTimeRangeSeconds;
    minimumPoseDiversityScore;
    samples = [];
    constructor(options = {}) {
        this.maxSamples = positiveInteger(options.maxSamples ?? 180, "maxSamples");
        this.minimumSamples = positiveInteger(options.minimumSamples ?? 8, "minimumSamples");
        this.minimumTimeRangeSeconds = nonNegativeFinite(options.minimumTimeRangeSeconds ?? 0.18, "minimumTimeRangeSeconds");
        this.minimumPoseDiversityScore = nonNegativeFinite(options.minimumPoseDiversityScore ?? 0.08, "minimumPoseDiversityScore");
    }
    record(sample) {
        validateSample(sample);
        this.samples.push(sample);
        if (this.samples.length > this.maxSamples) {
            this.samples.shift();
        }
        return this.report();
    }
    report() {
        return summarizeAnimationMotion(this.samples, {
            minimumSamples: this.minimumSamples,
            minimumTimeRangeSeconds: this.minimumTimeRangeSeconds,
            minimumPoseDiversityScore: this.minimumPoseDiversityScore
        });
    }
    reset() {
        this.samples.length = 0;
    }
}
export function summarizeAnimationMotion(samples, options = {}) {
    const minimumSamples = positiveInteger(options.minimumSamples ?? 8, "minimumSamples");
    const minimumTimeRangeSeconds = nonNegativeFinite(options.minimumTimeRangeSeconds ?? 0.18, "minimumTimeRangeSeconds");
    const minimumPoseDiversityScore = nonNegativeFinite(options.minimumPoseDiversityScore ?? 0.08, "minimumPoseDiversityScore");
    const ordered = samples.slice().sort((left, right) => left.timeSeconds - right.timeSeconds);
    const sampleCount = ordered.length;
    if (sampleCount === 0) {
        return emptyReport();
    }
    const firstTime = ordered[0].timeSeconds;
    const lastTime = ordered[sampleCount - 1].timeSeconds;
    const timeRangeSeconds = Math.max(0, lastTime - firstTime);
    const activeTrackFrames = ordered.filter((sample) => (sample.tracksApplied ?? 0) > 0).length;
    const activeSkinningFrames = ordered.filter((sample) => (sample.skinningPalettesUpdated ?? 0) > 0).length;
    const animatedSubjectFrames = ordered.filter((sample) => (sample.animatedSubjects ?? 0) > 0).length;
    const strides = ordered.map((sample) => Math.abs(sample.stride ?? 0));
    const averageStride = strides.reduce((sum, value) => sum + value, 0) / sampleCount;
    const poseDiversityScore = computePoseDiversity(ordered);
    return {
        sampleCount,
        timeRangeSeconds: round(timeRangeSeconds),
        activeTrackFrames,
        activeSkinningFrames,
        animatedSubjectFrames,
        averageStride: round(averageStride),
        poseDiversityScore: round(poseDiversityScore),
        healthy: sampleCount >= minimumSamples
            && timeRangeSeconds >= minimumTimeRangeSeconds
            && poseDiversityScore >= minimumPoseDiversityScore
            && (activeTrackFrames > 0 || activeSkinningFrames > 0 || animatedSubjectFrames > 0)
    };
}
function computePoseDiversity(samples) {
    if (samples.length < 2)
        return 0;
    let diversity = 0;
    for (let index = 1; index < samples.length; index += 1) {
        const previous = samples[index - 1];
        const current = samples[index];
        diversity += Math.abs(current.timeSeconds - previous.timeSeconds);
        diversity += Math.abs((current.tracksApplied ?? 0) - (previous.tracksApplied ?? 0)) * 0.01;
        diversity += Math.abs((current.skinningPalettesUpdated ?? 0) - (previous.skinningPalettesUpdated ?? 0)) * 0.01;
        diversity += Math.abs((current.stride ?? 0) - (previous.stride ?? 0));
        diversity += Math.abs((current.animatedSubjects ?? 0) - (previous.animatedSubjects ?? 0)) * 0.02;
    }
    return diversity;
}
function validateSample(sample) {
    nonNegativeFinite(sample.timeSeconds, "timeSeconds");
    optionalNonNegativeFinite(sample.tracksApplied, "tracksApplied");
    optionalNonNegativeFinite(sample.skinningPalettesUpdated, "skinningPalettesUpdated");
    optionalNonNegativeFinite(sample.stride, "stride");
    optionalNonNegativeFinite(sample.animatedSubjects, "animatedSubjects");
}
function optionalNonNegativeFinite(value, label) {
    if (value !== undefined)
        nonNegativeFinite(value, label);
}
function nonNegativeFinite(value, label) {
    if (!Number.isFinite(value) || value < 0) {
        throw new RangeError(`Animation motion ${label} must be finite and non-negative.`);
    }
    return value;
}
function positiveInteger(value, label) {
    if (!Number.isInteger(value) || value <= 0) {
        throw new RangeError(`Animation motion ${label} must be a positive integer.`);
    }
    return value;
}
function emptyReport() {
    return {
        sampleCount: 0,
        timeRangeSeconds: 0,
        activeTrackFrames: 0,
        activeSkinningFrames: 0,
        animatedSubjectFrames: 0,
        averageStride: 0,
        poseDiversityScore: 0,
        healthy: false
    };
}
function round(value) {
    return Number(value.toFixed(4));
}
//# sourceMappingURL=MotionQuality.js.map