import { APIRequestContext, test as base, request as playwrightRequest } from '@playwright/test';
import { readFileSync } from 'node:fs';

interface ManagerApiWorkerFixtures {
  managerApiRequest: APIRequestContext;
  billingApiRequest: APIRequestContext;
}

interface StorageStateFile {
  origins: { localStorage: { value: string }[] }[];
}

const STORAGE_STATE_PATH = '.auth/manager-admin-user.json';
const DEFAULT_MANAGER_API_URL = 'https://manager-api-test.kinnovis.com';
const DEFAULT_BILLING_API_URL = 'https://billing-api-test.kinnovis.com';

export const test = base.extend<object, ManagerApiWorkerFixtures>({
  managerApiRequest: [
    // oxlint-disable-next-line no-empty-pattern -- Playwright reads fixture dependencies from the destructured parameter
    async ({}, use) => {
      const ctx = await createAuthenticatedApiContext(process.env.MANAGER_API_URL ?? DEFAULT_MANAGER_API_URL);
      await use(ctx);
      await ctx.dispose();
    },
    { scope: 'worker' },
  ],

  // Booking create/cancel move to the billing API when the suite runs in modern (Kinnovis) billing mode —
  // mirrors the manager SPA, which routes those calls to the billing API for Kinnovis-billing tenants. The
  // billing API trusts the same bearer token as the manager API.
  billingApiRequest: [
    // oxlint-disable-next-line no-empty-pattern -- Playwright reads fixture dependencies from the destructured parameter
    async ({}, use) => {
      const ctx = await createAuthenticatedApiContext(process.env.BILLING_API_URL ?? DEFAULT_BILLING_API_URL);
      await use(ctx);
      await ctx.dispose();
    },
    { scope: 'worker' },
  ],
});

export { expect } from '@playwright/test';

function createAuthenticatedApiContext(baseURL: string): Promise<APIRequestContext> {
  const token = readBearerTokenFromStorageState(STORAGE_STATE_PATH);

  return playwrightRequest.newContext({
    baseURL,
    extraHTTPHeaders: {
      Authorization: `Bearer ${token}`,
      Accept: 'application/json',
    },
  });
}

// Scans every localStorage value for an `access_token` string — key- and nesting-agnostic
// so SPA refactors that rename the persist key or re-nest the token don't break us.
function readBearerTokenFromStorageState(path: string): string {
  const state = JSON.parse(readFileSync(path, 'utf8')) as StorageStateFile;

  for (const origin of state.origins) {
    for (const { value } of origin.localStorage) {
      const match = value.match(/"access_token":"([^"]+)"/);

      if (match) {
        return match[1];
      }
    }
  }

  throw new Error(`No access_token found in localStorage entries of ${path}`);
}
