// E2E regression for the inline notes composer color picker.
// The composer auto-saves on outside mousedown. Radix popovers render in
// a portal outside the composer's DOM, so picking a color used to count
// as an "outside click" and saved the note with the OLD color before the
// swatch's onClick had a chance to update state. This test guards that
// fix: pick a non-default color, click outside, then assert the saved
// note has that color.
import { test, expect } from "@playwright/test";
import pg from "pg";

const DATABASE_URL = process.env.DATABASE_URL;
if (!DATABASE_URL) {
  throw new Error("DATABASE_URL must be set to run this UI test");
}

const TEST_PASSWORD = "TestPass123!";
const TEST_PASSWORD_HASH =
  "$2b$10$Bs636ukPMyz01nKrsi.5m.JlDXSN22AVCvn8cgPWWDbo5yJRQX2vu";

const pool = new pg.Pool({ connectionString: DATABASE_URL });
const createdUserIds = [];

function uniq() {
  return `${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
}

async function createUser(prefix, displayEn) {
  const username = `${prefix}_${uniq()}`;
  const { rows } = await pool.query(
    `INSERT INTO users (username, email, password_hash, display_name_en, preferred_language, is_active)
     VALUES ($1, $2, $3, $4, 'en', true) RETURNING id`,
    [username, `${username}@example.com`, TEST_PASSWORD_HASH, displayEn],
  );
  const id = rows[0].id;
  createdUserIds.push(id);
  await pool.query(
    `INSERT INTO user_roles (user_id, role_id)
       SELECT $1, id FROM roles WHERE name = 'user'`,
    [id],
  );
  return { id, username };
}

test.afterAll(async () => {
  if (createdUserIds.length > 0) {
    await pool.query(`DELETE FROM notes WHERE user_id = ANY($1::int[])`, [
      createdUserIds,
    ]);
    await pool.query(`DELETE FROM user_roles WHERE user_id = ANY($1::int[])`, [
      createdUserIds,
    ]);
    await pool.query(`DELETE FROM users WHERE id = ANY($1::int[])`, [
      createdUserIds,
    ]);
  }
  await pool.end();
});

async function loginViaUi(page, username) {
  await page.goto("/login");
  await page.locator("#username").fill(username);
  await page.locator("#password").fill(TEST_PASSWORD);
  await Promise.all([
    page.waitForURL((url) => !url.pathname.endsWith("/login"), {
      timeout: 15_000,
    }),
    page.locator('form button[type="submit"]').click(),
  ]);
}

test("composer persists chosen color when saving via outside click", async ({
  page,
}) => {
  const user = await createUser("notes_color_e2e", "Color Tester");
  await loginViaUi(page, user.username);

  await page.goto("/notes");
  await expect(page.getByTestId("notes-page")).toBeVisible();

  // Open the composer and type some content.
  const content = `color-test ${uniq()}`;
  await page.getByTestId("notes-composer").click();
  await page.getByTestId("notes-composer-content").fill(content);

  // Open the color popover and pick a non-default swatch.
  await page
    .getByTestId("notes-composer")
    .locator('button[aria-label="Color"]')
    .click();
  // NOTE_COLORS[1] is the first non-default swatch ("red"); use it as the
  // target. The swatch button has aria-label set to its color id.
  const swatch = page.locator('[role="dialog"] button[aria-label="red"]')
    .or(page.locator('button[aria-label="red"]'));
  await swatch.first().click();

  // Click far outside the composer to trigger auto-save.
  const savePromise = page.waitForResponse(
    (r) =>
      new URL(r.url()).pathname === "/api/notes" &&
      r.request().method() === "POST" &&
      r.status() >= 200 &&
      r.status() < 300,
  );
  await page.mouse.click(10, 10);
  const resp = await savePromise;
  const note = await resp.json();

  expect(note.content).toBe(content);
  expect(note.color).toBe("red");
});
