import { AuthClient } from './auth.js';
import { Endpoint } from './endpoint.js';
import { subscribeTopic } from './subscribe.js';
import type {
  PicloudClientOptions,
  RealtimeEvent,
  SubscribeOptions,
  Unsubscribe
} from './types.js';

/**
 * The PiCloud frontend client. Three capabilities, all script-mediated
 * (the hybrid model — no direct KV/docs/users access from the browser):
 *
 *   - `endpoint<Req, Res>(path)` — typed HTTP to a dev-defined route.
 *   - `subscribe(topic, cb, opts?)` — SSE realtime subscription.
 *   - `auth` — login/logout/token helpers over dev-defined endpoints.
 */
export class PicloudClient {
  readonly auth: AuthClient;
  private readonly baseURL: string;
  private readonly fetchImpl: typeof fetch;
  private readonly getAuthToken: PicloudClientOptions['getAuthToken'];

  constructor(opts: PicloudClientOptions) {
    if (!opts.baseURL) throw new Error('PicloudClient: baseURL is required');
    this.baseURL = opts.baseURL;
    const f = opts.fetch ?? globalThis.fetch;
    if (typeof f !== 'function') {
      throw new Error('PicloudClient: no fetch available — pass options.fetch');
    }
    // Bind to avoid "Illegal invocation" when calling a detached global.
    this.fetchImpl = f.bind(globalThis);
    this.getAuthToken = opts.getAuthToken;
    this.auth = new AuthClient({ baseURL: this.baseURL, fetchImpl: this.fetchImpl });
  }

  /** A typed handle to a dev-defined endpoint. */
  endpoint<Req = unknown, Res = unknown>(path: string): Endpoint<Req, Res> {
    return new Endpoint<Req, Res>({
      baseURL: this.baseURL,
      path,
      getAuthToken: this.getAuthToken,
      fetchImpl: this.fetchImpl
    });
  }

  /** Subscribe to a realtime topic. Returns an unsubscribe function. */
  subscribe<T = unknown>(
    topic: string,
    onMessage: (event: RealtimeEvent<T>) => void,
    opts?: SubscribeOptions<T>
  ): Unsubscribe {
    return subscribeTopic<T>(
      { baseURL: this.baseURL, fetchImpl: this.fetchImpl },
      topic,
      onMessage,
      opts
    );
  }
}
