/**
 * E2E auth helpers.
 *
 * Strategy: API-login + localStorage injection. Faster and more reliable
 * than driving the Login form, and decouples route-coverage tests from
 * form-rendering flakiness. The Login form itself is exercised by the
 * existing manual / smoke flows.
 *
 * Zustand's `persist` middleware stores auth state under the
 * `auth-storage` key in localStorage. The shape is:
 *   { state: { token, user, offline }, version: 0 }
 *
 * Source of truth for demo credentials: server/src/database/init.js
 * (kept in sync with client/src/pages/Login.tsx's demoLogin() map).
 */
import { Page, request as pwRequest } from '@playwright/test';

export type PortalRole =
  | 'school_admin'
  | 'systems_admin'
  | 'principal'
  | 'hr'
  | 'bursar'
  | 'accountant'
  | 'nurse'
  | 'dining_staff'
  | 'teacher'
  | 'librarian'
  | 'clubs_head'
  | 'student'
  | 'parent'
  | 'driver'
  | 'groundsman'
  | 'matron'
  | 'boarding_master'
  | 'security'
  | 'janitor';

export const DEMO_ACCOUNTS: Record<PortalRole, { email: string; password: string }> = {
  systems_admin: { email: 'sysadmin@school.com', password: 'admin123' },
  school_admin:  { email: 'admin@school.com',   password: 'admin123' },
  principal:     { email: 'principal@school.com', password: 'principal123' },
  hr:            { email: 'hr@school.com',      password: 'hr123' },
  bursar:        { email: 'bursar@school.com',  password: 'bursar123' },
  accountant:    { email: 'bursar@school.com',  password: 'bursar123' }, // no seed; borrow bursar
  nurse:         { email: 'nurse@school.com',   password: 'nurse123' },
  dining_staff:  { email: 'dining@school.com',  password: 'dining123' },
  teacher:       { email: 'teacher@school.com', password: 'teacher123' },
  librarian:     { email: 'librarian@school.com', password: 'librarian123' },
  clubs_head:    { email: 'clubs_head@school.com', password: 'clubs123' },
  student:       { email: 'student@school.com', password: 'student123' },
  parent:        { email: 'parent@school.com',  password: 'parent123' },
  driver:        { email: 'driver@school.com',  password: 'driver123' },
  groundsman:    { email: 'groundsman@school.com', password: 'grounds123' },
  matron:        { email: 'matron@school.com',  password: 'matron123' },
  boarding_master: { email: 'boarding@school.com', password: 'boarding123' },
  security:      { email: 'security@school.com', password: 'security123' },
  janitor:       { email: 'janitor@school.com', password: 'janitor123' },
};

const API = 'http://localhost:3001';

export async function apiLogin(role: PortalRole): Promise<{ token: string; user: any }> {
  const account = DEMO_ACCOUNTS[role];
  if (!account) throw new Error(`No demo account for role ${role}`);
  const ctx = await pwRequest.newContext({ baseURL: API });
  try {
    const res = await ctx.post('/api/auth/login', { data: account });
    if (res.status() !== 200) {
      throw new Error(`Login failed for ${role} (${account.email}): ${res.status()} ${await res.text()}`);
    }
    const body = await res.json();
    return { token: body.token, user: body.user };
  } finally {
    await ctx.dispose();
  }
}

/**
 * Probe a demo account to see if it actually exists in the seed.
 * Used by specs to skip cleanly when the seed is minimal — the
 * helper itself doesn't fail, only the spec does.
 */
export async function isRoleAvailable(role: PortalRole): Promise<boolean> {
  try {
    await apiLogin(role);
    return true;
  } catch {
    return false;
  }
}

/**
 * Log `role` in by injecting the auth state into localStorage and
 * reloading the app. The baseURL is read from the Playwright config
 * (http://localhost:3000).
 *
 * The `?e2e=1` flag on the first navigation is honoured by AppLayout to
 * suppress notification permission requests and other side effects that
 * would otherwise interrupt the test run.
 */
export async function loginAs(page: Page, role: PortalRole): Promise<void> {
  const { token, user } = await apiLogin(role);
  await page.addInitScript(({ token, user }) => {
    const payload = { state: { token, user, offline: false }, version: 0 };
    window.localStorage.setItem('auth-storage', JSON.stringify(payload));
    // Suppress Notification.requestPermission() in AppLayout's effect.
    // The shim is a no-op so global notification polling becomes inert.
    (window as any).__E2E__ = true;
  }, { token, user });
}

export async function logout(page: Page): Promise<void> {
  await page.evaluate(() => {
    window.localStorage.removeItem('auth-storage');
  });
}
