// The single GatewayClient the app uses. In `mock` mode (pnpm start) it is the
// in-memory fake; otherwise it is the real Connect/FlatBuffers transport. MODE is a
// build-time constant, so a production build tree-shakes the mock away.

import type { GatewayClient } from './client';
import { MockGateway } from './mock/client';
import { createTransport } from './transport';
import { reportOffline, reportOnline } from './connection.svelte';
import { clearMaintenance, maintenanceRecovered, reportMaintenance } from './maintenance.svelte';

const isMock = import.meta.env.MODE === 'mock';

export const gateway: GatewayClient = isMock
  ? new MockGateway()
  : createTransport(import.meta.env.VITE_GATEWAY_URL ?? '');

// Mock-mode test hook (tree-shaken from a production build, where MODE !== 'mock'): the mock
// transport never exercises the connectivity indicator, so the Playwright e2e drives it directly.
if (isMock && typeof window !== 'undefined') {
  (window as unknown as { __conn?: { offline(): void; online(): void } }).__conn = {
    offline: reportOffline,
    online: reportOnline,
  };
  // The mock never produces a real 503, so the e2e drives the maintenance overlay directly
  // (the store's poll is inert in mock — no probe is registered — so `off` clears it).
  (
    window as unknown as { __maint?: { on(retryAfterMs?: number): void; off(): void; recover(): void } }
  ).__maint = {
    on: (retryAfterMs = 15000) => reportMaintenance(retryAfterMs),
    off: clearMaintenance,
    recover: maintenanceRecovered,
  };
  // Drive the auto-match opponent join deterministically from the e2e (the mock otherwise
  // attaches a robot on a timer).
  (
    window as unknown as {
      __mock?: {
        joinOpponent(): void;
        joinOpponentSilently(): void;
        adminReply(): void;
        setGameLimit(v: boolean): void;
        clearEmail(): void;
        confirmEmailOutOfBand(email: string): void;
      };
    }
  ).__mock = {
    joinOpponent: () => (gateway as MockGateway).joinPendingOpponent(),
    joinOpponentSilently: () => (gateway as MockGateway).joinPendingOpponentSilently(),
    adminReply: () => (gateway as MockGateway).mockAdminReply(),
    setGameLimit: (v: boolean) => (gateway as MockGateway).setGameLimit(v),
    clearEmail: () => (gateway as MockGateway).mockClearEmail(),
    confirmEmailOutOfBand: (email: string) => (gateway as MockGateway).mockConfirmEmailOutOfBand(email),
  };
}
