import { fireEvent, render, screen } from "@testing-library/react";
import { GlitchPlayer } from "./LecturePlayer";
import type {
  PresentationDefinition,
  SlideRegistry,
  SlideRuntimeProps
} from "../types/lecture";

const registry: SlideRegistry = {
  SquareYellow: async () => ({
    default: function MockSlide({ glitchSlideId }: SlideRuntimeProps) {
      return <div>{glitchSlideId}</div>;
    }
  })
};

const presentationFixture: PresentationDefinition = {
  id: "lecture-test",
  title: "Lecture test",
  version: "0.1.0",
  durationSec: 4,
  segments: [
    { id: "seg-1", src: "/seg-1.mp4", startTimeSec: 0, durationSec: 4 }
  ],
  slides: [
    {
      id: "slide-1",
      startTimeSec: 0,
      displayMode: "fullscreen",
      glitchSlides: [
        {
          id: "slide-1-a",
          score: 0.7,
          componentKey: "SquareYellow",
          props: {
            header: "TEST",
            imageSrc: "/test.png",
            imageAlt: "Test"
          }
        }
      ]
    }
  ]
};

const targetedPresentationFixture: PresentationDefinition = {
  id: "presentation-target-test",
  title: "Targeted slide preview",
  version: "0.1.0",
  durationSec: 6,
  segments: [
    { id: "seg-1", src: "/seg-1.mp4", startTimeSec: 0, durationSec: 6 }
  ],
  slides: [
    {
      id: "slide-1",
      startTimeSec: 0,
      endTimeSec: 2,
      displayMode: "square",
      glitchSlides: [
        {
          id: "slide-1-a",
          score: 0.7,
          componentKey: "SquareYellow",
          props: {
            header: "TEST",
            imageSrc: "/test.png",
            imageAlt: "Test"
          }
        }
      ]
    },
    {
      id: "slide-2",
      startTimeSec: 2,
      displayMode: "square",
      glitchSlides: [
        {
          id: "slide-2-a",
          score: 0.9,
          componentKey: "SquareYellow",
          props: {
            header: "TEST",
            imageSrc: "/test.png",
            imageAlt: "Test"
          }
        }
      ]
    }
  ]
};

const boundaryPresentationFixture: PresentationDefinition = {
  id: "presentation-boundary-test",
  title: "Boundary marker test",
  version: "0.1.0",
  durationSec: 9.6,
  segments: [
    { id: "seg-1", src: "/seg-1.mp4", startTimeSec: 0, durationSec: 9.6 }
  ],
  slides: [
    {
      id: "slide-1",
      startTimeSec: 0,
      endTimeSec: 3.2,
      displayMode: "square",
      glitchSlides: [
        {
          id: "slide-1-a",
          score: 0.7,
          componentKey: "SquareYellow",
          props: {
            header: "ONE",
            imageSrc: "/one.png",
            imageAlt: "One"
          }
        }
      ]
    },
    {
      id: "slide-2",
      startTimeSec: 3.2,
      endTimeSec: 4.8,
      displayMode: "fullscreen",
      glitchSlides: [
        {
          id: "slide-2-a",
          score: 0.8,
          componentKey: "SquareYellow",
          props: {
            header: "TWO",
            imageSrc: "/two.png",
            imageAlt: "Two"
          }
        }
      ]
    },
    {
      id: "slide-3",
      startTimeSec: 4.8,
      endTimeSec: 7.2,
      displayMode: "square",
      glitchSlides: [
        {
          id: "slide-3-a",
          score: 0.9,
          componentKey: "SquareYellow",
          props: {
            header: "THREE",
            imageSrc: "/three.png",
            imageAlt: "Three"
          }
        }
      ]
    }
  ]
};

const untimedPresentationFixture: PresentationDefinition = {
  id: "presentation-untimed-test",
  title: "Untimed slide preview",
  version: "0.1.0",
  durationSec: 6,
  segments: [
    { id: "seg-1", src: "/seg-1.mp4", startTimeSec: 0, durationSec: 6 }
  ],
  slides: [
    {
      id: "slide-untimed-1",
      startTimeSec: null,
      displayMode: "square",
      glitchSlides: [
        {
          id: "slide-untimed-1-a",
          score: 0.7,
          componentKey: "SquareYellow",
          props: {
            header: "ONE",
            imageSrc: "/one.png",
            imageAlt: "One"
          }
        }
      ]
    },
    {
      id: "slide-untimed-2",
      startTimeSec: null,
      displayMode: "fullscreen",
      glitchSlides: [
        {
          id: "slide-untimed-2-a",
          score: 0.9,
          componentKey: "SquareYellow",
          props: {
            header: "TWO",
            imageSrc: "/two.png",
            imageAlt: "Two"
          }
        }
      ]
    }
  ]
};

describe("GlitchPlayer", () => {
  it("renders fullscreen slide mode when the active slide requires it", async () => {
    render(
      <GlitchPlayer
        presentation={presentationFixture}
        slideRegistry={registry}
        initialSessionId="test-session"
      />
    );

    expect(await screen.findByTestId("slide-host-fullscreen")).toBeInTheDocument();
  });

  it("opens vote overlay when tapping a fullscreen slide", async () => {
    render(
      <GlitchPlayer
        presentation={presentationFixture}
        slideRegistry={registry}
        initialSessionId="test-session"
      />
    );

    const slideHost = await screen.findByTestId("slide-host-fullscreen");
    const gestureLayer = slideHost.closest(".lecture-player__gesture-layer");

    expect(gestureLayer).not.toBeNull();

    fireEvent.pointerDown(gestureLayer as Element, {
      pointerId: 1,
      clientX: 40,
      clientY: 40
    });
    fireEvent.pointerUp(gestureLayer as Element, {
      pointerId: 1,
      clientX: 40,
      clientY: 40
    });

    expect(
      await screen.findByRole("dialog", { name: "Vote on slide" })
    ).toBeInTheDocument();
  });

  it("can start in slide preview mode on a targeted slide", async () => {
    render(
      <GlitchPlayer
        presentation={targetedPresentationFixture}
        slideRegistry={registry}
        mode="slide-preview"
        targetSlideId="slide-2"
        initialSessionId="test-session"
      />
    );

    expect(await screen.findByText("slide-2-a")).toBeInTheDocument();
  });

  it("can start in slide preview mode on an untimed slide index", async () => {
    render(
      <GlitchPlayer
        presentation={untimedPresentationFixture}
        slideRegistry={registry}
        mode="slide-preview"
        targetSlideIndex={1}
        initialSessionId="test-session"
      />
    );

    expect(await screen.findByText("slide-untimed-2-a")).toBeInTheDocument();
  });

  it("stays paused after timeline scrubbing ends", async () => {
    render(
      <GlitchPlayer
        presentation={presentationFixture}
        slideRegistry={registry}
        initialSessionId="test-session"
      />
    );

    const scrubber = await screen.findByLabelText("Lecture timeline");

    fireEvent.pointerDown(scrubber, { pointerId: 1 });
    fireEvent.change(scrubber, { target: { value: "2" } });
    fireEvent.pointerUp(scrubber, { pointerId: 1 });

    expect(
      await screen.findByRole("button", { name: "Resume playback" })
    ).toBeInTheDocument();
  });

  it("jumps to a slide when clicking its timeline marker", async () => {
    render(
      <GlitchPlayer
        presentation={targetedPresentationFixture}
        slideRegistry={registry}
        initialSessionId="test-session"
      />
    );

    fireEvent.click(await screen.findByRole("button", { name: "S2" }));

    expect(await screen.findByText("slide-2-a")).toBeInTheDocument();
    expect(
      await screen.findByRole("button", { name: "Resume playback" })
    ).toBeInTheDocument();
  });

  it("selects the later boundary slide immediately when clicking consecutive markers", async () => {
    render(
      <GlitchPlayer
        presentation={boundaryPresentationFixture}
        slideRegistry={registry}
        initialSessionId="test-session"
      />
    );

    fireEvent.pointerDown(await screen.findByRole("button", { name: "S2" }));
    expect(await screen.findByText("slide-2-a")).toBeInTheDocument();

    fireEvent.pointerDown(await screen.findByRole("button", { name: "S3" }));
    expect(await screen.findByText("slide-3-a")).toBeInTheDocument();
  });
});
