import React from "react";
import { renderToStaticMarkup } from "react-dom/server";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { AllocationPopover } from "./AllocationPopover.js";

const mockUseQuery = vi.fn();
const mockUseMutation = vi.fn(() => ({ mutate: vi.fn() }));
const mockUseUtils = vi.fn(() => ({
  allocation: {
    getAssignmentById: { invalidate: vi.fn() },
    listView: { invalidate: vi.fn() },
  },
}));

vi.mock("~/lib/trpc/client.js", () => ({
  trpc: {
    useUtils: () => mockUseUtils(),
    allocation: {
      getAssignmentById: {
        useQuery: (...args: unknown[]) => mockUseQuery(...args),
      },
    },
    timeline: {
      updateAllocationInline: {
        useMutation: () => mockUseMutation(),
      },
      carveAllocationRange: {
        useMutation: () => mockUseMutation(),
      },
    },
  },
}));

vi.mock("~/hooks/useInvalidatePlanningViews.js", () => ({
  useInvalidateTimeline: () => vi.fn(),
}));

vi.mock("~/hooks/useViewportPopover.js", () => ({
  useViewportPopover: () => ({
    ref: { current: null },
    style: {},
  }),
}));

vi.mock("~/components/ui/DateInput.js", () => ({
  DateInput: () => null,
}));

vi.mock("~/components/ui/ProjectCombobox.js", () => ({
  ProjectCombobox: () => null,
}));

describe("AllocationPopover", () => {
  beforeEach(() => {
    mockUseQuery.mockReset();
    mockUseMutation.mockClear();
    mockUseUtils.mockClear();
  });

  it("renders an error state when the allocation lookup fails", () => {
    mockUseQuery.mockReturnValue({
      data: undefined,
      isLoading: false,
      error: new Error("Assignment not found"),
    });

    const html = renderToStaticMarkup(
      <AllocationPopover
        allocationId="assignment_missing"
        projectId="project_1"
        anchorX={120}
        anchorY={40}
        onClose={() => {}}
        onOpenPanel={() => {}}
      />,
    );

    expect(html).toContain("data-testid=\"timeline-allocation-popover-error\"");
    expect(html).toContain("The selected booking could not be loaded right now.");
    expect(html).toContain("Assignment not found");
  });

  it("renders an unavailable state when the lookup returns no allocation", () => {
    mockUseQuery.mockReturnValue({
      data: undefined,
      isLoading: false,
      error: null,
    });

    const html = renderToStaticMarkup(
      <AllocationPopover
        allocationId="assignment_missing"
        projectId="project_1"
        anchorX={120}
        anchorY={40}
        onClose={() => {}}
        onOpenPanel={() => {}}
      />,
    );

    expect(html).toContain("data-testid=\"timeline-allocation-popover-unavailable\"");
    expect(html).toContain("The selected booking could not be resolved from the current timeline data.");
  });

  it("renders a loading skeleton when the allocation is being fetched", () => {
    mockUseQuery.mockReturnValue({
      data: undefined,
      isLoading: true,
      error: null,
    });

    const html = renderToStaticMarkup(
      <AllocationPopover
        allocationId="assignment_loading"
        projectId="project_1"
        anchorX={120}
        anchorY={40}
        onClose={() => {}}
        onOpenPanel={() => {}}
      />,
    );

    expect(html).toContain("data-testid=\"timeline-allocation-popover-loading\"");
  });

  it("renders allocation data when provided as initialAllocation", () => {
    // useQuery is always called (with enabled: false), so we need a baseline return value
    mockUseQuery.mockReturnValue({
      data: undefined,
      isLoading: false,
      error: null,
    });

    const allocation = {
      id: "assignment_1",
      entityId: "assignment_1",
      projectId: "project_1",
      resourceId: "resource_1",
      startDate: new Date("2026-01-01"),
      endDate: new Date("2026-01-31"),
      hoursPerDay: 8,
      role: "Developer",
      metadata: null,
      resource: {
        displayName: "Alice Smith",
        eid: "alice.smith",
        lcrCents: 0,
      },
    };

    const html = renderToStaticMarkup(
      <AllocationPopover
        allocationId="assignment_1"
        projectId="project_1"
        initialAllocation={allocation as any}
        anchorX={120}
        anchorY={40}
        onClose={() => {}}
        onOpenPanel={() => {}}
      />,
    );

    expect(html).not.toContain("data-testid=\"timeline-allocation-popover-error\"");
    expect(html).not.toContain("data-testid=\"timeline-allocation-popover-unavailable\"");
    expect(html).not.toContain("data-testid=\"timeline-allocation-popover-loading\"");
  });
});
