import { describe, expect, it, vi } from "vitest";
import type { ToolcraftSourceAssetCoordinator } from "../../../source-assets/source-asset-coordinator";
import { createToolcraftSourceAssetPresentation } from "../../../source-assets/source-asset-presentation";
import { ToolcraftSourceAssetCoordinatorContext } from "../../app-shell/toolcraft-source-asset-context";
import {
  ControlsPanel,
  defineToolcraft,
  fireEvent,
  render,
  renderControlsPanelWithSchema,
  screen,
  ToolcraftRoot,
} from "../testing/controls-panel-test-utils";

describe("ControlsPanel media upload multi-image grid", () => {
  it("submits one complete multi-image selection to the coordinator", () => {
    const schema = defineToolcraft({
      canvas: { enabled: true, upload: true },
      panels: {
        controls: {
          sections: [
            {
              controls: {
                source: {
                  label: "Images",
                  multiple: true,
                  target: "input.sources",
                  type: "fileDrop",
                },
              },
              title: "Input",
            },
          ],
          title: "Generation Controls",
        },
      },
    });
    const importBatch = vi.fn<ToolcraftSourceAssetCoordinator["importBatch"]>(
      async () => ({
        assetIds: [] as const,
        kind: "committed" as const,
      }),
    );
    const idleOperation = Object.freeze({
      phase: "idle" as const,
      target: "input.sources",
    });
    const coordinator: ToolcraftSourceAssetCoordinator = {
      cancelTarget: vi.fn(),
      clearPresentationFeedback: vi.fn(),
      dispose: vi.fn(async () => undefined),
      getOperation: () => idleOperation,
      getPresentation: (control, mediaAssets, operation) =>
        createToolcraftSourceAssetPresentation(
          "image",
          control,
          mediaAssets,
          operation ?? idleOperation,
        ),
      hydrateBinaryMedia: vi.fn(async () => undefined),
      hydrateModels: vi.fn(async () => undefined),
      importBatch,
      repairModel: vi.fn(async () => ({ kind: "cancelled" as const })),
      reportPresentationFeedback: vi.fn(),
      subscribe: () => () => undefined,
    };

    const { container } = render(
      <ToolcraftRoot schema={schema}>
        <ToolcraftSourceAssetCoordinatorContext.Provider value={coordinator}>
          <ControlsPanel framed={false} />
        </ToolcraftSourceAssetCoordinatorContext.Provider>
      </ToolcraftRoot>,
    );
    const input = container.querySelector<HTMLInputElement>('input[type="file"]');
    const files = [
      new File(["one"], "one.png", { type: "image/png" }),
      new File(["two"], "two.png", { type: "image/png" }),
    ];

    fireEvent.change(input as HTMLInputElement, {
      target: { files },
    });

    expect(importBatch).toHaveBeenCalledTimes(1);
    expect(importBatch.mock.calls[0]?.[0]).toMatchObject({
      files,
      origin: "panel",
      target: "input.sources",
    });
    expect(importBatch.mock.calls[0]?.[1]).toMatchObject({
      target: "input.sources",
    });
  });

  it("renders multi-image file uploads as an add-last thumbnail grid", () => {
    const schema = defineToolcraft({
      canvas: { enabled: true, upload: true },
      panels: {
        controls: {
          sections: [
            {
              controls: {
                source: {
                  accept: "PNG, SVG",
                  label: "Images",
                  multiple: true,
                  target: "input.sources",
                  type: "fileDrop",
                },
              },
              layout: "standalone",
              title: "Input",
            },
          ],
          title: "Generation Controls",
        },
      },
    });

    const { container } = renderControlsPanelWithSchema(schema, undefined, {
      layers: [
        { id: "layer-1", kind: "layer", name: "one", visible: true },
        { id: "layer-2", kind: "layer", name: "two", visible: true },
      ],
      mediaAssets: [
        {
          dataUrl:
            "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 96 96'%3E%3Crect width='96' height='96' fill='%23777'/%3E%3C/svg%3E",
          fileName: "one.svg",
          id: "media-1",
          layerId: "layer-1",
          mimeType: "image/svg+xml",
          position: { x: 0, y: 0 },
          size: { height: 96, unit: "px", width: 96 },
        },
        {
          dataUrl:
            "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 96 96'%3E%3Crect width='96' height='96' fill='%23999'/%3E%3C/svg%3E",
          fileName: "two.svg",
          id: "media-2",
          layerId: "layer-2",
          mimeType: "image/svg+xml",
          position: { x: 0, y: 0 },
          size: { height: 96, unit: "px", width: 96 },
        },
      ],
      selectedLayerId: "layer-2",
    });

    expect(screen.getByRole("button", { name: "Add image files" })).toBeTruthy();
    const previewGrid = container.querySelector('[data-slot="file-upload-preview-grid"]');
    expect(previewGrid?.className).toContain("grid-cols-4");
    expect(previewGrid?.lastElementChild?.getAttribute("data-slot")).toBe(
      "file-upload-add-preview",
    );
    expect(screen.getByRole("img", { name: "one.svg" })).toBeTruthy();
    expect(screen.getByRole("img", { name: "two.svg" })).toBeTruthy();
    expect(screen.getByTestId("media-ids").textContent).toBe("media-1,media-2");
    expect(screen.queryByRole("button", { name: "90° Left" })).toBeNull();

    const firstPreview = screen
      .getByRole("img", { name: "one.svg" })
      .closest<HTMLElement>('[data-slot="file-upload-preview-item"]');
    const secondPreview = screen
      .getByRole("img", { name: "two.svg" })
      .closest<HTMLElement>('[data-slot="file-upload-preview-item"]');

    if (!firstPreview || !secondPreview) {
      throw new Error("Expected multi-image previews to render");
    }

    expect(firstPreview.getAttribute("role")).toBeNull();
    expect(screen.getByRole("button", { name: "Select one.svg" })).toBeTruthy();
    expect(screen.getByRole("button", { name: "Reorder one.svg" })).toBeTruthy();

    fireEvent.click(screen.getByRole("button", { name: "Select one.svg" }));
    expect(firstPreview.getAttribute("data-selected")).toBe("true");
    expect(screen.getByRole("button", { name: "90° Right" })).toBeTruthy();

    fireEvent.click(screen.getByRole("button", { name: "90° Right" }));
    expect(screen.getByTestId("media-transforms").textContent).toBe(
      '[{"rotationDeg":90},null]',
    );

    fireEvent.click(screen.getByRole("button", { name: "Remove two.svg" }));

    expect(screen.getByTestId("media-count").textContent).toBe("1");
    expect(screen.queryByRole("img", { name: "two.svg" })).toBeNull();
  });

  it("uses Layers selection for image transforms without rendering a duplicate media collection", () => {
    const schema = defineToolcraft({
      canvas: { enabled: true, upload: true },
      panels: {
        controls: {
          sections: [
            {
              controls: {
                source: {
                  assetKind: "image",
                  label: "Images",
                  multiple: true,
                  target: "input.sources",
                  type: "fileDrop",
                },
              },
              title: "Input",
            },
          ],
          title: "Generation Controls",
        },
        layers: true,
      },
    });

    const { container } = renderControlsPanelWithSchema(schema, undefined, {
      layers: [
        { id: "layer-1", kind: "layer", name: "one", visible: true },
        { id: "layer-2", kind: "layer", name: "two", visible: true },
      ],
      mediaAssets: [
        {
          dataUrl:
            "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 96 96'%3E%3Crect width='96' height='96' fill='%23777'/%3E%3C/svg%3E",
          fileName: "one.svg",
          id: "media-1",
          layerId: "layer-1",
          mimeType: "image/svg+xml",
          position: { x: 0, y: 0 },
          size: { height: 96, unit: "px", width: 96 },
          sourceTarget: "input.sources",
        },
        {
          dataUrl:
            "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 96 96'%3E%3Crect width='96' height='96' fill='%23999'/%3E%3C/svg%3E",
          fileName: "two.svg",
          id: "media-2",
          layerId: "layer-2",
          mimeType: "image/svg+xml",
          position: { x: 0, y: 0 },
          size: { height: 96, unit: "px", width: 96 },
          sourceTarget: "input.sources",
        },
      ],
      selectedLayerId: "layer-2",
    });

    expect(container.querySelector('input[type="file"]')).toBeTruthy();
    expect(
      container.querySelector('[data-slot="file-upload-preview-grid"]'),
    ).toBeNull();
    expect(
      container.querySelector('[data-slot="file-upload-file-list"]'),
    ).toBeNull();
    expect(screen.queryByRole("img", { name: "one.svg" })).toBeNull();
    expect(screen.queryByRole("img", { name: "two.svg" })).toBeNull();

    fireEvent.click(screen.getByRole("button", { name: "90° Right" }));
    fireEvent.click(screen.getByRole("button", { name: "Flip horizontal" }));
    fireEvent.click(screen.getByRole("button", { name: "Flip vertical" }));

    expect(screen.getByTestId("media-transforms").textContent).toBe(
      '[null,{"rotationDeg":90,"flipHorizontal":true,"flipVertical":true}]',
    );
  });
});
