/**
 * Water Log — end-to-end tests.
 *
 * These cover the user-visible surface of the Water Log feature across
 * both PIN-authenticated portals and the site-admin view. The intent is
 * to catch the most common production regressions: page no longer
 * renders, PIN screen broken, admin gate missing, CSV export leaking
 * unauthenticated data, etc.
 *
 * Heavy multi-actor flows (admin adds headgate → irrigator submits entry
 * → admin exports CSV) require a working DB + a fully-provisioned
 * Tuxedo brand, so they're behind a `WATER_LOG_E2E_DB=1` env flag. The
 * default suite stays runnable against any deployment.
 *
 * Run locally:
 *   PLAYWRIGHT_URL=http://localhost:3000 npx playwright test water-log
 *   # Or against prod (default in playwright.config):
 *   npx playwright test water-log
 */
import { test, expect, request } from "@playwright/test";

const BASE = process.env.PLAYWRIGHT_URL ?? "http://localhost:3000";

test.describe("Water Log — public surfaces", () => {
  test("/water renders the PIN entry form", async ({ page }) => {
    const res = await page.goto(`${BASE}/water`);
    expect(res?.status()).toBeLessThan(500);
    // PIN input is a password input with inputMode=numeric
    const pin = page.locator('input[type="password"][inputmode="numeric"]').first();
    await expect(pin).toBeVisible({ timeout: 10_000 });
  });

  test("/water PIN input strips non-digits and caps at 4 chars", async ({ page }) => {
    await page.goto(`${BASE}/water`);
    const pin = page.locator('input[type="password"][inputmode="numeric"]').first();
    await expect(pin).toBeVisible({ timeout: 10_000 });
    await pin.fill("12ab34cd56ef");
    const value = await pin.inputValue();
    expect(value).toMatch(/^\d{0,4}$/);
    expect(value.length).toBeLessThanOrEqual(4);
  });

  test("/water/admin renders the admin PIN entry form", async ({ page }) => {
    const res = await page.goto(`${BASE}/water/admin/login`);
    expect(res?.status()).toBeLessThan(500);
    const pin = page.locator('input[type="password"][inputmode="numeric"]').first();
    await expect(pin).toBeVisible({ timeout: 10_000 });
  });

  test("/water/admin wrong PIN shows an error, does not navigate", async ({ page }) => {
    await page.goto(`${BASE}/water/admin/login`);
    const pin = page.locator('input[type="password"][inputmode="numeric"]').first();
    await expect(pin).toBeVisible({ timeout: 10_000 });
    // Use a clearly-invalid 4-digit PIN. We don't know the configured
    // PIN, so 0000 is the canonical "wrong" value.
    await pin.fill("0000");
    const submit = page.getByRole("button", { name: /sign in|submit|enter/i }).first();
    if (await submit.isVisible().catch(() => false)) {
      await submit.click();
    } else {
      await pin.press("Enter");
    }
    // After a wrong PIN, the URL should still be the login page.
    await page.waitForTimeout(500);
    expect(page.url()).toMatch(/\/water\/admin\/login/);
  });
});

test.describe("Water Log — site-admin gate", () => {
  test("/admin/water-log redirects unauthenticated users", async ({ page }) => {
    await page.goto(`${BASE}/admin/water-log`, { waitUntil: "domcontentloaded" });
    // Should not stay on /admin/water-log if not signed in.
    expect(page.url()).not.toMatch(/\/admin\/water-log$/);
  });

  test("/admin/water-log/settings redirects unauthenticated users", async ({ page }) => {
    await page.goto(`${BASE}/admin/water-log/settings`, { waitUntil: "domcontentloaded" });
    expect(page.url()).not.toMatch(/\/admin\/water-log\/settings$/);
  });

  test("/admin/water-log/headgates redirects unauthenticated users", async ({ page }) => {
    await page.goto(`${BASE}/admin/water-log/headgates`, { waitUntil: "domcontentloaded" });
    expect(page.url()).not.toMatch(/\/admin\/water-log\/headgates$/);
  });

  test("/admin/water-log/users redirects unauthenticated users", async ({ page }) => {
    await page.goto(`${BASE}/admin/water-log/users`, { waitUntil: "domcontentloaded" });
    expect(page.url()).not.toMatch(/\/admin\/water-log\/users$/);
  });

  test("/admin/water-log/entries redirects unauthenticated users", async ({ page }) => {
    await page.goto(`${BASE}/admin/water-log/entries`, { waitUntil: "domcontentloaded" });
    expect(page.url()).not.toMatch(/\/admin\/water-log\/entries$/);
  });
});

test.describe("Water Log — API auth", () => {
  test("/api/water-logs/export returns 401/403 for unauthenticated callers", async () => {
    const ctx = await request.newContext({ baseURL: BASE });
    const res = await ctx.get("/api/water-logs/export");
    // Either 401 (no admin session) or 403 (signed in but not permitted)
    // — both are correct, the point is the endpoint doesn't leak data.
    expect([401, 403]).toContain(res.status());
    await ctx.dispose();
  });

  test("/api/water-admin-auth rejects malformed PINs (length != 4)", async () => {
    const ctx = await request.newContext({ baseURL: BASE });
    const res = await ctx.post("/api/water-admin-auth", {
      data: { brandId: "64294306-5f42-463d-a5e8-2ad6c81a96de", pin: "12" },
    });
    // 400 (bad request) or 401/403 (no admin user) — both are valid
    // gates. Critically, it must NOT be 200.
    expect(res.status()).not.toBe(200);
    await ctx.dispose();
  });

  test("/api/water-admin-auth rejects non-numeric PINs", async () => {
    const ctx = await request.newContext({ baseURL: BASE });
    const res = await ctx.post("/api/water-admin-auth", {
      data: { brandId: "64294306-5f42-463d-a5e8-2ad6c81a96de", pin: "abcd" },
    });
    expect(res.status()).not.toBe(200);
    await ctx.dispose();
  });
});

test.describe("Water Log — full workflow (DB required)", () => {
  // These tests need a live database with the Tuxedo brand provisioned
  // and the migrations from 0090 applied. Skipped by default so the
  // suite still runs against any deployment. Set WATER_LOG_E2E_DB=1
  // (and ensure BASE points at a dev DB) to opt in.
  test.skip(!process.env.WATER_LOG_E2E_DB, "requires WATER_LOG_E2E_DB=1 + a live DB");

  test("site admin can add a headgate and an irrigator, then export CSV", async ({ page }) => {
    // 1. Sign in as a platform_admin or Tuxedo brand_admin
    await page.goto(`${BASE}/login`);
    // The login flow is environment-specific (Google OAuth, email link,
    // or local dev session). Try the dev session form first.
    const emailInput = page.getByLabel(/email/i).first();
    if (await emailInput.isVisible().catch(() => false)) {
      await emailInput.fill(process.env.WATER_LOG_TEST_ADMIN_EMAIL ?? "admin@tuxedo.example");
      const passwordInput = page.getByLabel(/password/i).first();
      if (await passwordInput.isVisible().catch(() => false)) {
        await passwordInput.fill(process.env.WATER_LOG_TEST_ADMIN_PASSWORD ?? "test-password");
      }
      await page.getByRole("button", { name: /sign in/i }).first().click();
    }

    // 2. Navigate to the Water Log admin
    await page.goto(`${BASE}/admin/water-log`);
    await expect(page.getByRole("heading", { name: /water log/i }).first()).toBeVisible({
      timeout: 15_000,
    });

    // 3. Add a headgate
    const hgName = `E2E Headgate ${Date.now()}`;
    const addHg = page.getByRole("button", { name: /add headgate/i }).first();
    if (await addHg.isVisible().catch(() => false)) {
      await addHg.click();
      const nameInput = page.getByPlaceholder(/north field gate|gate/i).first();
      await nameInput.fill(hgName);
      await page.getByRole("button", { name: /^save|create|add$/i }).first().click();
    }
    await expect(page.getByText(hgName).first()).toBeVisible({ timeout: 10_000 });

    // 4. Add an irrigator
    const irrName = `E2E Irrigator ${Date.now()}`;
    const addUser = page.getByRole("button", { name: /add (water )?user|add irrigator/i }).first();
    if (await addUser.isVisible().catch(() => false)) {
      await addUser.click();
      const nameInput = page.getByPlaceholder(/full name/i).first();
      await nameInput.fill(irrName);
      await page.getByRole("button", { name: /^save|create|add$/i }).first().click();
    }
    await expect(page.getByText(irrName).first()).toBeVisible({ timeout: 10_000 });

    // 5. Hit the CSV export endpoint and confirm it returns CSV
    const ctx = await request.newContext({
      baseURL: BASE,
      storageState: await page.context().storageState(),
    });
    const res = await ctx.get("/api/water-logs/export?format=csv");
    expect(res.status()).toBe(200);
    const contentType = res.headers()["content-type"] ?? "";
    expect(contentType).toContain("text/csv");
    const body = await res.text();
    expect(body.split("\n").length).toBeGreaterThanOrEqual(1);
    await ctx.dispose();
  });
});
