// OAuth — native provider sign-in as a typed service plugin (docs/backend-plan.md §3.4). The
// browser broker (`auth.oauth.url()` on the server + `openURL` in the app) works everywhere; on
// hosts that ship a provider SDK (Yandex LoginSDK, VK ID, Sign in with Apple, Google Sign-In) the
// user shouldn't leave the app — the host registers an "oauth" service that runs the native sheet
// and hands back the provider's CREDENTIAL. The app then calls its own endpoint, which does
// `auth.oauth.signIn(provider, credential)`: the server verifies the credential with the provider
// (audience = the platform's app ids) and binds the device session. No token is ever trusted
// client-side; the credential is opaque to the app.
//
// Host-OPTIONAL — gate on `OAuth.isSupported(provider)`; fall back to the browser broker otherwise.
//
// Service contract ("oauth"): call `signIn(provider) → OAuthCredential` (rejects "cancelled" /
// "unavailable"), call `providers() → string[]` (which providers this host has SDKs for).

import { ServiceClient } from "../runtime/service"

export type OAuthProviderName = "google" | "apple" | "yandex" | "vk"

/** What a native provider SDK yields — pass it verbatim to your endpoint / `auth.oauth.signIn`. */
export type OAuthCredential = {
  provider: OAuthProviderName
  /** OAuth access token (Yandex, VK ID). */
  accessToken?: string
  /** OpenID identity token (Google, Apple). */
  idToken?: string
  /** Apple only sends the name once, on the first sign-in — forward it so the server can store it. */
  name?: string
  email?: string
}

/**
 * Native provider sign-in. `OAuth.isSupported` reports whether this host registered the service;
 * `OAuth.providers()` which providers it has SDKs for. Otherwise open `auth.oauth.url(provider)` (server)
 * with `openURL` — the browser broker.
 */
// PURE IIFE so an app that never uses it tree-shakes the plugin away (see Geolocation).
export const OAuth: {
  /** Whether this host registered an "oauth" service. */
  readonly isSupported: boolean
  /** The providers this host can sign in with natively. */
  providers(): Promise<OAuthProviderName[]>
  /** Run the provider's native sheet; resolves with the credential for `auth.oauth.signIn`. Rejects "cancelled" / "unavailable". */
  signIn(provider: OAuthProviderName): Promise<OAuthCredential>
} = /*#__PURE__*/ (() => {
  let client: ServiceClient | null = null
  const service = (): ServiceClient => client ??= new ServiceClient("oauth")
  const assertSupported = (): void => {
    if (!ServiceClient.isSupported("oauth")) {
      throw new Error("OAuth isn't available on this host — it needs a registered \"oauth\" service; open auth.oauth.url(provider) in the browser instead.")
    }
  }
  return {
    get isSupported() { return ServiceClient.isSupported("oauth") },
    providers: async () => { assertSupported(); const p = await service().call("providers"); return Array.isArray(p) ? p : [] },
    signIn: async (provider) => {
      assertSupported()
      const r = await service().call("signIn", provider)
      return { provider, ...(r ?? {}) }
    },
  }
})()
