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

// E2E smoke for the V2 cross-space calendar (top-bar "カレンダー" tab).
//
// Drives the real orchestrator with auth off → synthetic 'local' admin, who can
// see every space and edit events. We create a case space, add an event for
// today via the per-space calendar (reusing its tested flow), then open the
// top-bar Calendar tab and assert the cross view shows that space's dot on
// today and groups the day panel by space.
//
// Benign-path allowlist mirrors spaces.spec.ts: with auth disabled the UI's
// /api/auth/me probe 404s on purpose; org/MCP/ssh probes 401/404. All benign.

const BENIGN_PATHS = new Set([
  '/api/auth/me',
  '/api/users/me/orgs',
  '/api/mcp/connections',
  '/api/mcp/servers',
  '/api/mcp/user-servers',
  '/api/ssh/connections',
]);
const BENIGN_ASSET = /\.(ico|png|svg|map|webmanifest|json)$/i;
const BENIGN_PATH_RE =
  /\/api\/local\/tasks\/\d+\/console\/status$|\/api\/local\/browser\/sessions\/task-session\/\d+$/;

function trackFatalErrors(page: Page): string[] {
  const fatalErrors: string[] = [];
  page.on('pageerror', (err) => fatalErrors.push(`pageerror: ${err.message}`));
  page.on('response', (res) => {
    if (res.status() >= 400) {
      const { pathname } = new URL(res.url());
      if (!BENIGN_ASSET.test(pathname) && !BENIGN_PATHS.has(pathname) && !BENIGN_PATH_RE.test(pathname)) {
        fatalErrors.push(`HTTP ${res.status()} ${res.url()}`);
      }
    }
  });
  return fatalErrors;
}

/** Viewer-local 'YYYY-MM-DD' today, matching the UI's localToday(). */
function e2eLocalToday(): string {
  const d = new Date();
  const mm = String(d.getMonth() + 1).padStart(2, '0');
  const dd = String(d.getDate()).padStart(2, '0');
  return `${d.getFullYear()}-${mm}-${dd}`;
}

async function createAndOpenCaseSpace(page: Page, label: string) {
  await page.goto('/ui');
  await page.getByTestId('nav-spaces').click();
  const rail = page.getByTestId('space-rail');
  await expect(rail).toBeVisible();

  await page.getByTestId('create-space-btn').click();
  const titleInput = page.getByTestId('space-title-input');
  await expect(titleInput).toBeVisible();
  const caseTitle = `${label}-${Date.now()}`;
  await titleInput.fill(caseTitle);
  await page.getByTestId('create-space-submit').click();
  await expect(titleInput).toHaveCount(0);

  const caseRow = rail
    .locator('[data-testid="space-row"][data-space-kind="case"]')
    .filter({ hasText: caseTitle });
  await expect(caseRow).toBeVisible();
  const spaceId = await caseRow.getAttribute('data-space-id');
  expect(spaceId).toBeTruthy();
  await caseRow.click();
  await expect(page.getByTestId('space-detail')).toBeVisible();
  return { caseTitle, spaceId: spaceId as string };
}

/** Add an event for today in the currently-open space's calendar tab. */
async function addTodayEvent(page: Page, title: string) {
  await page.getByTestId('space-tab-calendar').click();
  await expect(page.getByTestId('space-cal-grid')).toBeVisible();
  const today = e2eLocalToday();
  await page.getByTestId(`space-cal-day-${today}`).click();
  const panel = page.getByTestId('space-cal-day-panel');
  await expect(panel).toBeVisible();
  await panel.getByTestId('space-cal-add-event-btn').click();
  const form = page.getByTestId('space-cal-add-event');
  await expect(form).toBeVisible();
  await form.getByTestId('space-cal-event-title').fill(title);
  await form.getByTestId('space-cal-event-time').fill('11:00');
  await form.getByTestId('space-cal-event-save').click();
  await expect(panel.getByText(title, { exact: true })).toBeVisible({ timeout: 10_000 });
}

test('cross calendar: top-bar tab opens, grid renders, month nav works', async ({ page }) => {
  const fatalErrors = trackFatalErrors(page);
  await page.goto('/ui');

  await page.getByTestId('nav-calendar').click();
  await expect(page.getByTestId('cross-calendar')).toBeVisible();
  await expect(page.getByTestId('cross-cal-grid')).toBeVisible();
  await expect(page).toHaveURL(/[?&]page=calendar(&|$)/);

  // today's cell exists
  await expect(page.getByTestId(`cross-cal-day-${e2eLocalToday()}`)).toBeVisible();

  // month nav flips the YYYY年M月 header and returns
  const title = page.getByTestId('cross-cal-title');
  const initial = (await title.textContent())?.trim();
  expect(initial).toMatch(/\d{4}年\d{1,2}月/);
  await page.getByTestId('cross-cal-next').click();
  await expect(title).not.toHaveText(initial!);
  await page.getByTestId('cross-cal-prev').click();
  await expect(title).toHaveText(initial!);

  expect(fatalErrors, `fatal errors:\n${fatalErrors.join('\n')}`).toEqual([]);
});

test('cross calendar: a space with activity shows its dot + day panel groups by space', async ({ page }) => {
  const fatalErrors = trackFatalErrors(page);
  const { caseTitle, spaceId } = await createAndOpenCaseSpace(page, 'E2E横断カレンダー');
  const eventTitle = `横断予定-${Date.now()}`;
  await addTodayEvent(page, eventTitle);

  // Open the top-bar cross calendar.
  await page.getByTestId('nav-calendar').click();
  await expect(page.getByTestId('cross-cal-grid')).toBeVisible();

  const today = e2eLocalToday();
  const todayCell = page.getByTestId(`cross-cal-day-${today}`);
  // Today's cell carries the activity dot for our space.
  await expect(todayCell.getByTestId(`cross-cal-dot-${spaceId}`)).toBeVisible({ timeout: 10_000 });

  // Click the day → panel grouped by space, with our space heading + its event.
  await todayCell.click();
  const panel = page.getByTestId('cross-cal-day-panel');
  await expect(panel).toBeVisible();
  const spaceGroup = panel.getByTestId(`cross-cal-space-${spaceId}`);
  await expect(spaceGroup).toBeVisible();
  await expect(spaceGroup.getByText(caseTitle, { exact: true })).toBeVisible();
  await expect(spaceGroup.getByText(eventTitle, { exact: true })).toBeVisible({ timeout: 10_000 });

  expect(fatalErrors, `fatal errors:\n${fatalErrors.join('\n')}`).toEqual([]);
});
