/**
 * Playwright fixtures for real SSO authentication testing.
 *
 * Extends Playwright's base test with auth-specific fixtures:
 * - ssoApi: Direct SSO API client for fast auth operations
 * - loginAs: Helper to login as a test account
 * - logout: Helper to logout and clear session
 * - getSessionToken: Get current session token from browser
 * - authenticatedPage: Page already logged in as worker
 *
 * @example
 * ```typescript
 * import { test, expect } from '@platform/e2e-auth';
 *
 * test('should show dashboard when logged in', async ({ loginAs, page }) => {
 *   await loginAs('worker');
 *   await page.goto('/dashboard');
 *   await expect(page.locator('h1')).toContainText('Dashboard');
 * });
 * ```
 */

import { test as base, expect, type Page } from '@playwright/test';
import { SSOApiClient, type LoginResponse } from './sso-api-client';
import { TEST_ACCOUNTS, type TestAccountRole } from './test-accounts';

const SSO_URL = process.env.SSO_URL || 'http://localhost:4001';
const SESSION_STORAGE_KEY = 'lilith_session';

/**
 * Auth-specific test fixtures.
 */
export interface AuthFixtures {
  /** Direct SSO API client for fast auth operations */
  ssoApi: SSOApiClient;

  /**
   * Login as a test account.
   *
   * Performs login via API and sets session in browser localStorage.
   * This is faster than UI login for test setup.
   *
   * @param role - Test account role ('worker', 'client', 'admin')
   * @returns Login response with session and user
   */
  loginAs: (role: TestAccountRole) => Promise<LoginResponse>;

  /**
   * Logout and clear session.
   *
   * Calls logout API and clears localStorage.
   */
  logout: () => Promise<void>;

  /**
   * Get current session token from browser localStorage.
   *
   * @returns Session token or null if not logged in
   */
  getSessionToken: () => Promise<string | null>;

  /**
   * Page already logged in as worker.
   *
   * Use this fixture when you don't need to test login flow itself.
   */
  authenticatedPage: Page;
}

/**
 * Extended test with auth fixtures.
 */
export const test = base.extend<AuthFixtures>({
  // SSO API client
  ssoApi: async ({}, use) => {
    const client = new SSOApiClient({ baseUrl: SSO_URL });

    // Verify SSO is reachable
    const healthy = await client.healthCheck();
    if (!healthy) {
      throw new Error(`SSO service is not reachable at ${SSO_URL}`);
    }

    await use(client);
  },

  // Login helper
  loginAs: async ({ page, ssoApi }, use) => {
    let currentSession: string | null = null;

    const loginFn = async (role: TestAccountRole): Promise<LoginResponse> => {
      const account = TEST_ACCOUNTS[role];

      // Login via API (faster than UI)
      const response = await ssoApi.login({
        email: account.email,
        password: account.password,
      });

      currentSession = response.sessionId;

      // Set session in browser localStorage
      await page.evaluate(
        ({ key, value }) => {
          localStorage.setItem(key, value);
        },
        { key: SESSION_STORAGE_KEY, value: response.sessionId }
      );

      return response;
    };

    await use(loginFn);

    // Cleanup: logout if we logged in
    if (currentSession) {
      try {
        await ssoApi.logout(currentSession);
      } catch {
        // Ignore logout errors in cleanup
      }
    }
  },

  // Logout helper
  logout: async ({ page, ssoApi, getSessionToken }, use) => {
    const logoutFn = async () => {
      const token = await getSessionToken();

      // Clear localStorage first
      await page.evaluate((key) => {
        localStorage.removeItem(key);
      }, SESSION_STORAGE_KEY);

      // Call logout API if we have a session
      if (token) {
        try {
          await ssoApi.logout(token);
        } catch {
          // Ignore - session may already be invalid
        }
      }
    };

    await use(logoutFn);
  },

  // Get session token helper
  getSessionToken: async ({ page }, use) => {
    const getTokenFn = async (): Promise<string | null> => {
      return page.evaluate((key) => localStorage.getItem(key), SESSION_STORAGE_KEY);
    };

    await use(getTokenFn);
  },

  // Pre-authenticated page
  authenticatedPage: async ({ page, loginAs }, use) => {
    // Login as worker by default
    await loginAs('worker');
    await use(page);
  },
});

export { expect };
