import { isEFTemporal } from "./EFTemporal.ts";
import type { EFTimegroup } from "./EFTimegroup.ts";

export const updateAnimations = (
  element: HTMLElement & {
    currentTimeMs: number;
    durationMs: number;
    rootTimegroup?: EFTimegroup;
    parentTimegroup?: EFTimegroup;
    startTimeMs: number;
    endTimeMs: number;
  },
) => {
  element.style.setProperty(
    "--ef-progress",
    `${Math.max(0, Math.min(1, element.currentTimeMs / element.durationMs)) * 100}%`,
  );
  const timelineTimeMs = (element.rootTimegroup ?? element).currentTimeMs;
  if (
    element.startTimeMs > timelineTimeMs ||
    element.endTimeMs < timelineTimeMs
  ) {
    element.style.display = "none";
    return;
  }
  element.style.display = "";

  // Check if getAnimations is available (Web Animations API - not available in Node.js)
  if (typeof element.getAnimations !== "function") {
    return;
  }

  const animations = element.getAnimations({ subtree: true });
  element.style.setProperty("--ef-duration", `${element.durationMs}ms`);
  element.style.setProperty(
    "--ef-transition-duration",
    `${element.parentTimegroup?.overlapMs ?? 0}ms`,
  );
  element.style.setProperty(
    "--ef-transition-out-start",
    `${element.durationMs - (element.parentTimegroup?.overlapMs ?? 0)}ms`,
  );

  for (const animation of animations) {
    if (animation.playState === "running") {
      animation.pause();
    }
    const effect = animation.effect;
    if (!(effect && effect instanceof KeyframeEffect)) {
      continue;
    }
    const target = effect.target;
    // TODO: better generalize work avoidance for temporal elements
    if (!target) {
      continue;
    }
    if (target.closest("ef-timegroup") !== element) {
      continue;
    }

    const timing = effect.getTiming();
    const duration = Number(timing.duration) ?? 0;
    const delay = Number(timing.delay) ?? 0;
    const iterations = Number(timing.iterations) ?? 1;

    const timeTarget = isEFTemporal(target)
      ? target
      : target.closest("ef-timegroup");
    if (!timeTarget) {
      continue;
    }

    const currentTime = timeTarget.ownCurrentTimeMs;

    // Handle delay - don't start animation until delay is complete
    if (currentTime < delay) {
      animation.currentTime = 0;
      continue;
    }

    const currentIteration = Math.floor((currentTime - delay) / duration);
    const currentIterationTime = (currentTime - delay) % duration;

    if (currentIteration >= iterations) {
      // Stop just before the end to prevent DOM removal
      animation.currentTime = duration - 0.01;
      continue;
    }

    // Ensure we never reach exactly duration
    animation.currentTime =
      Math.min(currentIterationTime, duration - 0.01) + delay;
  }
};
