import { test, expect, type Page } from '@playwright/test';
import { createRequire } from 'node:module';
import { fileURLToPath } from 'node:url';
import { dirname, resolve, join } from 'node:path';
import { tmpdir } from 'node:os';

// ── M0: WORKSPACE FILE → AGENT INPUT E2E ─────────────────────────────────────
//
// Covers the user-observable parts of M0 (spec:
// docs/superpowers/specs/2026-06-24-workspace-consolidation-m0-file-input-consistency-design.md):
//
//   1. Creating a case workspace through the UI scaffolds files/input + files/output
//      (scaffoldCaseSpace) — they show up as folders in the Files tab right away.
//   2. The new-chat dialog warns (data-testid="ephemeral-warning") when the user
//      switches the workspace mode to 一時的 (ephemeral), and hides it for the
//      default 永続 (persistent).
//
// "The agent actually sees pre-placed files" is asserted by the unit test
// (src/engine/agent-loop.test.ts → buildSystemPrompt existing workspace files),
// since asserting LLM behaviour end-to-end is non-deterministic.
//
// Runs with LOCAL AUTH on (ui/playwright.auth.config.ts → config.e2e-auth.yaml)
// against the real built server. Seeds one regular user via the built Repository
// into the same deterministic DB the webServer opens.

const __dirname = dirname(fileURLToPath(import.meta.url));
const require = createRequire(import.meta.url);
const repoRoot = resolve(__dirname, '..', '..');

const e2eTmp = join(tmpdir(), 'maestro-e2e-auth');
const DB_PATH = join(e2eTmp, 'e2e-auth.db');

const USER = { email: 'wsfile@m0.local', password: 'WsFile123!', name: 'WsFileUser' };

async function login(page: Page, email: string, password: string) {
  await page.goto('/auth/login');
  await page.fill('input[name="email"]', email);
  await page.fill('input[name="password"]', password);
  await Promise.all([
    page.waitForURL(/\/ui(\/|$)/, { timeout: 15_000 }),
    page.click('button[type="submit"]'),
  ]);
  expect(page.url(), 'login should not bounce back to /auth/login').not.toContain('/auth/login');
}

/** Create a fresh case workspace via the UI (this is what triggers scaffoldCaseSpace). */
async function createAndOpenCaseSpace(page: Page, label: string): Promise<void> {
  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 title = `${label}-${Date.now()}`;
  await titleInput.fill(title);
  await page.getByTestId('space-form-submit').click();
  await expect(titleInput).toHaveCount(0);
  const caseRow = rail
    .locator('[data-testid="space-row"][data-space-kind="case"]')
    .filter({ hasText: title });
  await expect(caseRow).toBeVisible();
  await caseRow.click();
  await expect(page.getByTestId('space-detail')).toBeVisible();
}

test.beforeAll(async () => {
  const { Repository } = require(resolve(repoRoot, 'dist/db/repository.js')) as {
    Repository: new (dbPath: string) => {
      getUserByEmail: (email: string) => { id: string } | null;
      createLocalUser: (p: { email: string; password: string; name?: string; role: string; status: string }) => { id: string };
      close?: () => void;
    };
  };
  const repo = new Repository(DB_PATH);
  try {
    if (!repo.getUserByEmail(USER.email)) {
      repo.createLocalUser({ email: USER.email, password: USER.password, name: USER.name, role: 'user', status: 'active' });
    }
  } finally {
    repo.close?.();
  }
});

test('new case workspace shows input/ and output/ folders in the Files tab', async ({ page }) => {
  await login(page, USER.email, USER.password);
  await createAndOpenCaseSpace(page, 'm0-files');

  await page.getByTestId('space-tab-files').click();
  await expect(page.getByTestId('space-files')).toBeVisible();

  const inputTile = page.locator('[data-testid="space-file-tile"][data-kind="directory"][data-name="input"]');
  const outputTile = page.locator('[data-testid="space-file-tile"][data-kind="directory"][data-name="output"]');
  await expect(inputTile).toBeVisible({ timeout: 15_000 });
  await expect(outputTile).toBeVisible();
});

test('fresh workspace chat list shows next-action guidance, and ＋新規 opens the create dialog (step 3 entry)', async ({ page }) => {
  await login(page, USER.email, USER.password);
  await createAndOpenCaseSpace(page, 'm0-step3');

  // The chat tab is the default. A brand-new workspace has no chats, so the
  // empty state should guide the user to send a request and explain where files
  // and outputs live (step 3 / step 4 next-action copy).
  await expect(page.getByTestId('space-tab-chat')).toBeVisible();
  await expect(page.getByText('「＋ 新規」からエージェントに依頼を送れます')).toBeVisible();
  await expect(page.getByText(/成果物は ファイルタブの output\/ に保存されます/)).toBeVisible();

  // Step 3 entry: the ＋新規 button opens the create dialog (no LLM run needed —
  // we only assert the entry point reaches the dialog).
  await page.getByTestId('space-new-chat-btn').click();
  await expect(page.getByTestId('ephemeral-warning')).toHaveCount(0); // dialog open, persistent default
  await expect(page.getByRole('button', { name: /永続/ })).toBeVisible();
});

test('opening a fresh chat surfaces step 4 guidance: artifacts live in the output/ folder', async ({ page }) => {
  await login(page, USER.email, USER.password);
  await createAndOpenCaseSpace(page, 'm0-step4');

  // Step 3 → create a chat through the dialog. No LLM runs in this env
  // (e2e-noop worker), so the job never completes — we only verify the
  // create → open → "where do artifacts go" path, which is step 4's next-action.
  await page.getByTestId('space-new-chat-btn').click();
  await page.getByTestId('create-task-body').fill('step4 の成果物の在りかを確認するためのチャット');
  await page.getByTestId('create-task-submit').click();

  // The created chat opens inline (handleSpaceCreate → onSelectSpaceTask).
  await expect(page.getByTestId('space-conversation')).toBeVisible({ timeout: 15_000 });

  // Open the Files tab of the opened chat, then switch to the output/ section.
  // Brand-new chat → output/ is empty → the step 4 hint explains where the
  // agent's artifacts will land. (The FileBrowser section switcher buttons are
  // plain-text 'workspace'/'input'/'output'/'logs'.)
  await page.getByTestId('space-chat-tab-files').click();
  await page.getByRole('button', { name: 'output', exact: true }).click();
  await expect(page.getByTestId('output-empty-hint')).toBeVisible({ timeout: 15_000 });
  await expect(page.getByTestId('output-empty-hint')).toContainText('output/');
});

test('new-chat dialog warns when ephemeral mode is selected, not for persistent', async ({ page }) => {
  await login(page, USER.email, USER.password);
  await createAndOpenCaseSpace(page, 'm0-warn');

  await page.getByTestId('space-new-chat-btn').click();

  // Default is persistent → no warning.
  await expect(page.getByTestId('ephemeral-warning')).toHaveCount(0);

  // Switch to 一時的 → warning appears.
  await page.getByRole('button', { name: '一時的' }).click();
  await expect(page.getByTestId('ephemeral-warning')).toBeVisible();

  // Switch back to 永続 → warning gone.
  await page.getByRole('button', { name: /永続/ }).click();
  await expect(page.getByTestId('ephemeral-warning')).toHaveCount(0);
});
