import { Task } from "@lit/task";

import type { VideoSample } from "mediabunny";
import { IgnorableError } from "../../EFMedia";
import type { EFVideo } from "../../EFVideo";
import type { BufferedSeekingInput } from "../BufferedSeekingInput";

type VideoSeekTask = Task<
  readonly [number, BufferedSeekingInput | undefined],
  VideoSample | undefined
>;
export const makeVideoSeekTask = (host: EFVideo): VideoSeekTask => {
  return new Task(host, {
    args: () => [host.desiredSeekTimeMs, host.videoInputTask.value] as const,
    onError: (error) => {
      if (error instanceof IgnorableError) {
        console.info("videoSeekTask aborted");
      }
      console.error("videoSeekTask error", error);
    },
    onComplete: (_value) => {},
    task: async (
      [targetSeekTimeMs],
      { signal },
    ): Promise<VideoSample | undefined> => {
      await host.mediaEngineTask.taskComplete;
      signal.throwIfAborted(); // Abort if a new seek started
      await host.videoSegmentIdTask.taskComplete;
      signal.throwIfAborted(); // Abort if a new seek started
      await host.videoSegmentFetchTask.taskComplete;
      signal.throwIfAborted(); // Abort if a new seek started
      await host.videoInitSegmentFetchTask.taskComplete;
      signal.throwIfAborted(); // Abort if a new seek started

      const videoInput = await host.videoInputTask.taskComplete;
      signal.throwIfAborted(); // Abort if a new seek started
      if (!videoInput) {
        throw new Error("Video input is not available");
      }
      const videoTrack = await videoInput.getFirstVideoTrack();
      if (!videoTrack) {
        throw new Error("Video track is not available");
      }
      signal.throwIfAborted(); // Abort if a new seek started

      const sample = (await videoInput.seek(
        videoTrack.id,
        targetSeekTimeMs, // Use the captured value, not host.desiredSeekTimeMs
      )) as unknown as VideoSample | undefined;

      signal.throwIfAborted(); // Abort if a new seek started
      // If seek returned undefined, it was aborted - don't throw
      if (sample === undefined && signal.aborted) {
        return undefined;
      }

      // If we got undefined but weren't aborted, that's an actual error
      if (sample === undefined) {
        throw new Error("Video seek failed to find sample");
      }

      return sample;
    },
  });
};
