import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { QueryToolbar, queryShortcut } from "./QueryToolbar";
import { useDbViewerStore } from "../../stores/dbViewerStore";
import { TooltipProvider } from "../ui/Tooltip";

function renderToolbar(props: {
  onRun?: () => void;
  onFormat?: () => void;
  dbType?: "postgresql" | "mysql" | "sqlite" | "redis";
  connectionId?: string;
  onRestore?: (sql: string) => void;
  onRunFromHistory?: (sql: string) => void;
}) {
  return render(
    <TooltipProvider>
      <QueryToolbar
        onRun={props.onRun ?? (() => {})}
        onFormat={props.onFormat ?? (() => {})}
        dbType={props.dbType}
        connectionId={props.connectionId ?? "conn-1"}
        onRestore={props.onRestore ?? (() => {})}
        onRunFromHistory={props.onRunFromHistory ?? (() => {})}
      />
    </TooltipProvider>,
  );
}

describe("queryShortcut", () => {
  afterEach(() => {
    Object.defineProperty(navigator, "platform", {
      value: "",
      configurable: true,
    });
  });

  it("uses the command symbol and enter glyph on mac", () => {
    expect(queryShortcut("MacIntel")).toEqual({ mod: "⌘", enter: "⏎" });
  });

  it("uses Ctrl + Enter on other platforms", () => {
    expect(queryShortcut("Win32")).toEqual({ mod: "Ctrl", enter: "Enter" });
    expect(queryShortcut("Linux x86_64")).toEqual({
      mod: "Ctrl",
      enter: "Enter",
    });
  });

  it("renders the mac shortcut in the run tooltip", async () => {
    Object.defineProperty(navigator, "platform", {
      value: "MacIntel",
      configurable: true,
    });
    renderToolbar({});
    fireEvent.mouseEnter(
      screen.getByRole("button", { name: /run query/i }).parentElement!,
    );
    await waitFor(() => expect(screen.getByText("⌘")).toBeInTheDocument());
    expect(screen.getByText("⏎")).toBeInTheDocument();
  });

  it("renders Ctrl + Enter in the run tooltip on non-mac", async () => {
    Object.defineProperty(navigator, "platform", {
      value: "Linux x86_64",
      configurable: true,
    });
    renderToolbar({});
    fireEvent.mouseEnter(
      screen.getByRole("button", { name: /run query/i }).parentElement!,
    );
    await waitFor(() => expect(screen.getByText("Ctrl")).toBeInTheDocument());
    expect(screen.getByText("Enter")).toBeInTheDocument();
  });
});

describe("QueryToolbar", () => {
  beforeEach(() => {
    useDbViewerStore.getState().reset();
  });

  const baseProps = {
    onRun: () => {},
    onFormat: () => {},
    connectionId: "conn-1",
    onRestore: () => {},
    onRunFromHistory: () => {},
  };

  it("shows a Cancel button when isRunning is true", () => {
    render(
      <TooltipProvider>
        <QueryToolbar {...baseProps} isRunning={true} onCancel={() => {}} />
      </TooltipProvider>,
    );
    expect(screen.getByRole("button", { name: /cancel/i })).toBeTruthy();
  });

  it("hides the Cancel button when not running", () => {
    render(
      <TooltipProvider>
        <QueryToolbar {...baseProps} isRunning={false} onCancel={() => {}} />
      </TooltipProvider>,
    );
    expect(screen.queryByRole("button", { name: /cancel/i })).toBeNull();
  });

  it("renders Run Query and the format icon button", () => {
    renderToolbar({});
    expect(
      screen.getByRole("button", { name: /run query/i }),
    ).toBeInTheDocument();
    expect(
      screen.getByRole("button", { name: /auto format/i }),
    ).toBeInTheDocument();
  });

  it("shows the SQL dialect on the right", () => {
    renderToolbar({ dbType: "postgresql" });
    expect(screen.getByText("PostgreSQL")).toBeInTheDocument();
    renderToolbar({ dbType: "mysql" });
    expect(screen.getByText("MySQL")).toBeInTheDocument();
  });

  it("hides the dialect badge when no db type is known", () => {
    renderToolbar({});
    expect(screen.queryByText(/postgresql|mysql|sqlite|redis/i)).toBeNull();
  });

  it("runs the query when Run Query is clicked", () => {
    const onRun = vi.fn();
    renderToolbar({ onRun });
    fireEvent.click(screen.getByRole("button", { name: /run query/i }));
    expect(onRun).toHaveBeenCalledTimes(1);
  });

  it("calls onFormat when the format icon is clicked", () => {
    const onFormat = vi.fn();
    renderToolbar({ onFormat });
    fireEvent.click(screen.getByRole("button", { name: /auto format/i }));
    expect(onFormat).toHaveBeenCalledTimes(1);
  });

  it("starts with an unfilled play icon", () => {
    renderToolbar({});
    const playSvg = screen
      .getByRole("button", { name: /run query/i })
      .querySelector("svg");
    expect(playSvg).toHaveAttribute("fill", "none");
  });

  it("shows the pulse while the active query tab is loading", () => {
    useDbViewerStore.getState().openQueryTab();
    useDbViewerStore.setState((s) => ({
      tabs: s.tabs.map((t) => ({ ...t, loading: true })),
    }));
    renderToolbar({});
    expect(screen.getByTestId("query-run-pulse")).toBeInTheDocument();
  });

  it("hides the pulse when the query is idle", () => {
    useDbViewerStore.getState().openQueryTab();
    renderToolbar({});
    expect(screen.queryByTestId("query-run-pulse")).toBeNull();
  });

  it("renders the format action as an icon only (no text label)", () => {
    renderToolbar({});
    const button = screen.getByRole("button", { name: /auto format/i });
    expect(button.textContent?.trim()).toBe("");
  });

  it("renders History icon button", () => {
    renderToolbar({});
    expect(screen.getByLabelText("Query history")).toBeInTheDocument();
  });

  it("renders Save Query icon button", () => {
    renderToolbar({});
    expect(screen.getByLabelText("Save query")).toBeInTheDocument();
  });

  it("orders toolbar actions: Run, History, Format, Save", () => {
    renderToolbar({});
    const container = screen.getByLabelText("Query toolbar actions");
    const buttons = Array.from(container.querySelectorAll("button"));
    const btnLabels = buttons.map((b) => b.getAttribute("aria-label"));
    // Run Query first, then History, then Auto Format, then Save
    expect(btnLabels[0]).toBe("Run query");
    expect(btnLabels[1]).toBe("Query history");
    expect(btnLabels[2]).toBe("Auto format query");
    expect(btnLabels[3]).toBe("Save query");
  });
});