import { expect, test, type Page } from "@playwright/test";

async function signInAsAdmin(page: Page) {
  await page.goto("/auth/signin");
  await page.fill('input[type="email"]', "admin@capakraken.dev");
  await page.fill('input[type="password"]', "admin123");
  await page.click('button[type="submit"]');
  await expect(page).toHaveURL(/\/(dashboard|resources)/);
}

test.describe("Timeline", () => {
  test.describe.configure({ mode: "serial" });

  test.beforeEach(async ({ page }) => {
    await page.addInitScript(() => {
      localStorage.setItem("capakraken_theme", JSON.stringify({ mode: "dark" }));
    });
    await signInAsAdmin(page);
    await page.goto("/timeline");
  });

  test("loads and displays the timeline", async ({ page }) => {
    await expect(page.locator("text=Resource view")).toBeVisible();
    await expect(page.locator("text=Project view")).toBeVisible();
    await expect(page.getByRole("button", { name: /All Clients|Clients:/ })).toBeVisible();
    await expect(page.getByRole("button", { name: /All Chapters|Chapters:/ })).toBeVisible();
    await expect(page.getByRole("button", { name: /All people|People:/ })).toBeVisible();
    // Timeline canvas should be visible
    await expect(page.locator("div.app-surface.relative.flex-1.overflow-auto")).toBeVisible();
  });

  test("can switch between resource and project view", async ({ page }) => {
    await page.click("text=Project view");
    await expect(
      page.locator("text=0 projects").or(page.locator("text=/\\d+ projects/")),
    ).toBeVisible();
    await page.click("text=Resource view");
    await expect(page.locator("text=/\\d+ resources/")).toBeVisible();
  });

  test("can navigate forward and back", async ({ page }) => {
    const todayBtn = page.locator("button", { hasText: "Today" });
    await expect(todayBtn).toBeVisible();
    await page.locator("button", { hasText: "›" }).click();
    await page.locator("button", { hasText: "‹" }).click();
    await todayBtn.click();
  });

  test("filter panel opens and closes", async ({ page }) => {
    await page.locator("button", { hasText: "Filter" }).click();
    await expect(page.getByRole("heading", { name: "Filters" })).toBeVisible();
    await expect(page.getByPlaceholder("Search projects…")).toBeVisible();
    await page.keyboard.press("Escape");
    await expect(page.getByRole("heading", { name: "Filters" })).not.toBeVisible();
  });

  test("shows placeholder bars for unassigned allocations", async ({ page }) => {
    // Filter to show placeholders (enabled by default)
    // The timeline should have at least one dashed placeholder bar from seed data
    await page.waitForSelector(".overflow-auto", { state: "visible" });
    // Check that the timeline loaded (resource rows or empty state visible)
    await expect(
      page.locator(".app-toolbar").getByText(/\d+ resources · \d+ allocations/),
    ).toBeVisible();
  });

  test("clicking a placeholder opens the fill placeholder modal", async ({ page }) => {
    // Wait for timeline to load
    await page.waitForSelector(".overflow-auto");
    await page.waitForTimeout(1000); // let tRPC queries settle

    // Try to find and click a placeholder bar (dashed border style)
    const placeholderBar = page.locator("[style*='dashed']").first();
    if ((await placeholderBar.count()) > 0) {
      await placeholderBar.click();
      await expect(
        page.locator("text=Fill Placeholder").or(page.locator("text=Assign Resource")),
      ).toBeVisible();
      await page.keyboard.press("Escape");
    }
  });

  test("resource and project views keep tooltips opaque in dark mode and support right click", async ({
    page,
  }) => {
    await page.waitForSelector(".overflow-auto", { state: "visible" });
    await page.waitForTimeout(1000);

    const heatmapTooltip = page
      .locator("div.fixed.pointer-events-none.rounded-xl.border.border-gray-800")
      .first();
    const allocationPopoverField = page.getByText("Hours / day");

    const resourceHoverTarget = page.getByTestId("timeline-resource-row-canvas").first();
    const resourceHoverBox = await resourceHoverTarget.boundingBox();
    expect(resourceHoverBox).not.toBeNull();
    if (!resourceHoverBox) {
      throw new Error("Expected a resource timeline row canvas to be available");
    }
    await page.mouse.move(resourceHoverBox.x + 120, resourceHoverBox.y + 20);
    await expect(heatmapTooltip).toBeVisible();
    await expect
      .poll(async () => {
        return heatmapTooltip.evaluate((element) => getComputedStyle(element).backgroundColor);
      })
      .toBe("rgba(3, 7, 18, 0.96)");

    const resourceAllocation = page
      .locator(
        "div.absolute.rounded-md.flex.items-stretch.overflow-hidden.transition-all.duration-75",
      )
      .first();
    await resourceAllocation.click({ button: "right" });
    await expect(allocationPopoverField).toBeVisible();
    await page.mouse.click(40, 40);

    await page.getByText("Project view").click();
    await expect(page.getByText(/projects/)).toBeVisible();
    await page.waitForTimeout(500);

    const projectHoverTarget = page.getByTestId("timeline-project-resource-row-canvas").first();
    const projectHoverBox = await projectHoverTarget.boundingBox();
    const projectAllocation = page.locator("div[style*='top: 2px'][style*='bottom: 2px']").nth(1);
    const projectAllocationBox = await projectAllocation.boundingBox();
    expect(projectHoverBox).not.toBeNull();
    expect(projectAllocationBox).not.toBeNull();
    if (!projectHoverBox) {
      throw new Error("Expected a project timeline row canvas to be available");
    }
    if (!projectAllocationBox) {
      throw new Error("Expected a project allocation block to be available");
    }
    await page.mouse.move(projectAllocationBox.x + (projectAllocationBox.width / 2), projectHoverBox.y + 20);
    await expect(heatmapTooltip).toBeVisible();
    await expect
      .poll(async () => {
        return heatmapTooltip.evaluate((element) => getComputedStyle(element).backgroundColor);
      })
      .toBe("rgba(3, 7, 18, 0.96)");

    await projectAllocation.click({ button: "right" });
    await expect(allocationPopoverField).toBeVisible();
  });

  test("shows resolved holiday overlays in the resource timeline and exposes the holiday name in the tooltip", async ({
    page,
  }) => {
    await page.goto("/timeline?startDate=2026-04-01&days=14&eids=bruce.banner", {
      waitUntil: "domcontentloaded",
    });

    const row = page.locator('[data-testid="timeline-resource-row-canvas"][data-resource-eid="bruce.banner"]').first();
    await expect(row).toBeVisible();

    const holidayBlock = row.locator(
      '[data-testid="timeline-vacation-block"][data-vacation-type="PUBLIC_HOLIDAY"][data-vacation-note="Karfreitag"]',
    ).first();
    await expect(holidayBlock).toBeVisible();

    const rowBox = await row.boundingBox();
    const holidayBox = await holidayBlock.boundingBox();
    expect(rowBox).not.toBeNull();
    expect(holidayBox).not.toBeNull();

    if (!rowBox || !holidayBox) {
      throw new Error("Expected timeline row and holiday block bounding boxes to be available");
    }

    await row.hover({
      position: {
        x: holidayBox.x - rowBox.x + holidayBox.width / 2,
        y: holidayBox.y - rowBox.y + Math.min(holidayBox.height / 2, rowBox.height - 4),
      },
    });

    const holidayTooltip = page
      .locator("div.fixed.pointer-events-none.rounded-xl.border.border-amber-700\\/50")
      .or(page.locator("div.fixed.pointer-events-none.rounded-xl").filter({ hasText: "Karfreitag" }))
      .first();

    await expect(holidayTooltip).toBeVisible();
    await expect(holidayTooltip).toContainText("Karfreitag");
    await expect(holidayTooltip).toContainText("3 April 2026");
  });
});
