import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";

import { ToolcraftRoot } from "../app-shell/toolcraft-root";
import {
  createTimelineSchema,
  installTimelinePanelTestEnvironment,
  renderTimelinePanel,
} from "./timeline-panel-test-utils";
import { TimelinePanel } from "./timeline-panel";

installTimelinePanelTestEnvironment();

type RectFixture = {
  bottom: number;
  height: number;
  left: number;
  right: number;
  top: number;
  width: number;
  x?: number;
  y?: number;
};

function makeRect({ bottom, height, left, right, top, width, x = left, y = top }: RectFixture) {
  return {
    bottom,
    height,
    left,
    right,
    toJSON: () => ({}),
    top,
    width,
    x,
    y,
  } as DOMRect;
}

const emptyRect = makeRect({
  bottom: 0,
  height: 0,
  left: 0,
  right: 0,
  top: 0,
  width: 0,
});

describe("TimelinePanel floating layout", () => {
  it("delegates the whole timeline window size to motion during expand and collapse", () => {
    const { container } = renderTimelinePanel({ panelPlacement: "floating" });
    const timelinePanel = container.querySelector<HTMLElement>('[data-slot="timeline-panel"]');

    expect(timelinePanel?.style.width).toBe("256px");
    expect(timelinePanel?.style.height).toBe("36px");

    fireEvent.click(screen.getByRole("button", { name: "Expand timeline panel" }));

    expect(timelinePanel?.getAttribute("data-expanded-height")).toBe("110");

    fireEvent.click(screen.getByRole("button", { name: "Collapse timeline panel" }));

    expect(timelinePanel?.getAttribute("data-expanded-height")).toBeNull();
  });

  it("uses the shared panel host when floating", () => {
    const { container } = renderTimelinePanel({ panelPlacement: "floating" });

    expect(container.querySelector('[data-panel-type="timeline"]')).toBeTruthy();
    expect(container.querySelector('[data-snap-edges="top bottom"]')).toBeTruthy();
  });

  it("moves the expanded floating timeline from the stable host position before narrowing", async () => {
    vi.spyOn(HTMLElement.prototype, "getBoundingClientRect").mockImplementation(function (
      this: HTMLElement,
    ) {
      if (this.matches('[data-slot="toolcraft-runtime-app"]')) {
        return makeRect({
          bottom: 720,
          height: 720,
          left: 0,
          right: 960,
          top: 0,
          width: 960,
        });
      }

      if (this.matches('[data-panel-type="controls"]')) {
        return makeRect({
          bottom: 560,
          height: 560,
          left: 10,
          right: 40,
          top: 10,
          width: 30,
        });
      }

      if (this.matches('[data-panel-type="layers"]')) {
        return makeRect({
          bottom: 560,
          height: 560,
          left: 760,
          right: 950,
          top: 10,
          width: 190,
        });
      }

      if (
        this.matches('[data-slot="toolcraft-runtime-panel-host"]') &&
        this.matches('[data-panel-type="timeline"]')
      ) {
        return makeRect({
          bottom: 128,
          height: 118,
          left: 136,
          right: 824,
          top: 10,
          width: 688,
        });
      }

      if (this.matches('[data-slot="timeline-panel"]')) {
        return makeRect({
          bottom: 128,
          height: 118,
          left: 99,
          right: 787,
          top: 10,
          width: 688,
        });
      }

      return emptyRect;
    });

    const { container } = render(
      <ToolcraftRoot
        initialState={{ timeline: { expanded: true } }}
        schema={createTimelineSchema()}
      >
        <div data-slot="toolcraft-runtime-app">
          <div data-panel-type="controls" />
          <div data-panel-type="layers" />
          <TimelinePanel framed={false} panelPlacement="floating" />
        </div>
      </ToolcraftRoot>,
    );

    const timelinePanel = container.querySelector<HTMLElement>('[data-slot="timeline-panel"]');

    await waitFor(() => {
      expect(timelinePanel?.getAttribute("data-responsive-offset-x")).toBe("-74");
      expect(timelinePanel?.getAttribute("data-responsive-width")).toBeNull();
    });
  });

  it("narrows expanded floating timeline after it reaches both side panels", async () => {
    vi.spyOn(HTMLElement.prototype, "getBoundingClientRect").mockImplementation(function (
      this: HTMLElement,
    ) {
      if (this.matches('[data-slot="toolcraft-runtime-app"]')) {
        return makeRect({
          bottom: 720,
          height: 720,
          left: 0,
          right: 960,
          top: 0,
          width: 960,
        });
      }

      if (this.matches('[data-panel-type="layers"]')) {
        return makeRect({
          bottom: 560,
          height: 560,
          left: 10,
          right: 250,
          top: 10,
          width: 240,
        });
      }

      if (this.matches('[data-panel-type="controls"]')) {
        return makeRect({
          bottom: 560,
          height: 560,
          left: 650,
          right: 950,
          top: 10,
          width: 300,
        });
      }

      if (this.matches('[data-slot="timeline-panel"]')) {
        return makeRect({
          bottom: 128,
          height: 118,
          left: 136,
          right: 824,
          top: 10,
          width: 688,
        });
      }

      return emptyRect;
    });

    const { container } = render(
      <ToolcraftRoot
        initialState={{ timeline: { expanded: true } }}
        schema={createTimelineSchema()}
      >
        <div data-slot="toolcraft-runtime-app">
          <div data-panel-type="layers" />
          <div data-panel-type="controls" />
          <TimelinePanel framed={false} panelPlacement="floating" />
        </div>
      </ToolcraftRoot>,
    );

    const timelinePanel = container.querySelector<HTMLElement>('[data-slot="timeline-panel"]');

    await waitFor(() => {
      expect(timelinePanel?.getAttribute("data-responsive-offset-x")).toBe("-30");
      expect(timelinePanel?.getAttribute("data-responsive-width")).toBe("380");
    });
  });

  it("keeps the expanded floating timeline inside the side-panel corridor immediately after resize", async () => {
    let isNarrow = false;

    vi.spyOn(HTMLElement.prototype, "getBoundingClientRect").mockImplementation(function (
      this: HTMLElement,
    ) {
      if (this.matches('[data-slot="toolcraft-runtime-app"]')) {
        return makeRect({
          bottom: 720,
          height: 720,
          left: 0,
          right: isNarrow ? 1024 : 1440,
          top: 0,
          width: isNarrow ? 1024 : 1440,
        });
      }

      if (this.matches('[data-panel-type="layers"]')) {
        return makeRect({
          bottom: 560,
          height: 560,
          left: 10,
          right: 250,
          top: 10,
          width: 240,
        });
      }

      if (this.matches('[data-panel-type="controls"]')) {
        return makeRect({
          bottom: 560,
          height: 560,
          left: isNarrow ? 714 : 1130,
          right: isNarrow ? 1014 : 1430,
          top: 10,
          width: 300,
          x: isNarrow ? 714 : 1130,
        });
      }

      if (
        this.matches('[data-slot="toolcraft-runtime-panel-host"]') &&
        this.matches('[data-panel-type="timeline"]')
      ) {
        return makeRect({
          bottom: 128,
          height: 118,
          left: isNarrow ? 384 : 592,
          right: isNarrow ? 640 : 848,
          top: 10,
          width: 256,
          x: isNarrow ? 384 : 592,
        });
      }

      if (this.matches('[data-slot="timeline-panel"]')) {
        return makeRect({
          bottom: 128,
          height: 118,
          left: isNarrow ? 384 : 592,
          right: isNarrow ? 640 : 848,
          top: 10,
          width: 256,
          x: isNarrow ? 384 : 592,
        });
      }

      return emptyRect;
    });

    const { container } = render(
      <ToolcraftRoot
        initialState={{ timeline: { expanded: true } }}
        schema={createTimelineSchema()}
      >
        <div data-slot="toolcraft-runtime-app">
          <div data-panel-type="layers" />
          <div data-panel-type="controls" />
          <TimelinePanel framed={false} panelPlacement="floating" />
        </div>
      </ToolcraftRoot>,
    );

    const timelinePanel = container.querySelector<HTMLElement>('[data-slot="timeline-panel"]');

    await waitFor(() => {
      expect(timelinePanel?.getAttribute("data-responsive-width")).toBeNull();
      expect(timelinePanel?.getAttribute("data-responsive-offset-x")).toBeNull();
    });

    isNarrow = true;
    fireEvent(window, new Event("resize"));

    await waitFor(() => {
      expect(timelinePanel?.getAttribute("data-responsive-width")).toBe("444");
      expect(timelinePanel?.getAttribute("data-responsive-offset-x")).toBe("-30");
    });
  });
});
