/**
 * Desktop-only surfaces that have no web equivalent in V1 (ticket #13, lot F1):
 * the native folder picker, OS view-windows and the main↔detached focused-project
 * channel, plus SSH/WSL remote. On the web client these must fail with a clear,
 * explicit error rather than reaching for Tauri (which is absent).
 *
 * The B0 inventory classified these as `desktop-only`; F1 does NOT implement them
 * for web. If/when the product wants an equivalent (e.g. a server-side folder
 * browser to replace `pickFolder`), it gets its own lot.
 */

import type {
  EmbeddedServerStatus,
  GatewayError,
  ServerExposurePreview,
  ServerExposureSettings,
  Unsubscribe,
} from "@/domain";
import type {
  DesktopServerGateway,
  FocusedProject,
  FocusedProjectGateway,
  RemoteGateway,
  ViewWindowClosed,
  ViewWindowSnapshot,
  WindowGateway,
} from "@/ports";

/** Throws a stable, explicit "unsupported on web" {@link GatewayError}. */
export function unsupportedOnWeb(what: string): never {
  const err: GatewayError = {
    code: "UNSUPPORTED_ON_WEB",
    message: `${what} is not available in the web client (desktop-only).`,
  };
  throw err;
}

/** Web stub: OS view-windows are desktop-only (no `WebviewWindow` on the web). */
export class WebWindowGateway implements WindowGateway {
  openViewWindow(): Promise<void> {
    return unsupportedOnWeb("Detaching a panel into an OS window");
  }
  closeViewWindow(): Promise<void> {
    return unsupportedOnWeb("Closing a detached OS window");
  }
  listOpenViewWindows(): Promise<ViewWindowSnapshot[]> {
    // Best-effort by contract (callers treat rejection as "no reconciliation"),
    // but there are simply never detached OS windows on web → empty list.
    return Promise.resolve([]);
  }
  onViewWindowClosed(
    _handler: (event: ViewWindowClosed) => void,
  ): Promise<Unsubscribe> {
    // No OS windows ⇒ nothing ever fires; return a no-op unsubscribe.
    return Promise.resolve(() => {});
  }
}

/**
 * Web stub for the focused-project channel. With no detached windows on web the
 * channel has no cross-window consumer; F1 keeps it inert (no publish, no focus).
 * A future multi-tab web build could back this with `BroadcastChannel`.
 */
export class WebFocusedProjectGateway implements FocusedProjectGateway {
  setFocusedProject(_project: FocusedProject | null): Promise<void> {
    // No-op: nothing reads the channel on web V1.
    return Promise.resolve();
  }
  getFocusedProject(): Promise<FocusedProject | null> {
    return Promise.resolve(null);
  }
  onFocusedProjectChanged(
    _handler: (project: FocusedProject | null) => void,
  ): Promise<Unsubscribe> {
    return Promise.resolve(() => {});
  }
}

/** Web stub: SSH/WSL remote connection is desktop-only in V1. */
export class WebRemoteGateway implements RemoteGateway {
  connect(): Promise<void> {
    return unsupportedOnWeb("Remote (SSH/WSL) connection");
  }
}

/**
 * Web stub: the embedded server is desktop-only (ticket #68). A web client is
 * *served by* this very server, so letting it reconfigure or stop the server
 * would let a remote device saw off the branch it sits on. The desktop app owns
 * this surface; every call fails explicitly rather than reaching for Tauri.
 */
export class WebDesktopServerGateway implements DesktopServerGateway {
  // `async` on purpose: these must *reject* rather than throw synchronously, so
  // callers using `.then(ok, err)` (not just `await`) still see the failure.
  async getExposureSettings(): Promise<ServerExposureSettings> {
    return unsupportedOnWeb("Embedded server settings");
  }
  async saveExposureSettings(_settings: ServerExposureSettings): Promise<void> {
    return unsupportedOnWeb("Embedded server settings");
  }
  async previewExposure(
    _settings: ServerExposureSettings,
  ): Promise<ServerExposurePreview> {
    return unsupportedOnWeb("Embedded server settings");
  }
  async status(): Promise<EmbeddedServerStatus> {
    return unsupportedOnWeb("Embedded server status");
  }
  async start(): Promise<EmbeddedServerStatus> {
    return unsupportedOnWeb("Starting the embedded server");
  }
  async stop(): Promise<EmbeddedServerStatus> {
    return unsupportedOnWeb("Stopping the embedded server");
  }
  onStatusChanged(
    _handler: (status: EmbeddedServerStatus) => void,
  ): Promise<Unsubscribe> {
    // Never fires on web; a no-op unsubscribe keeps callers' teardown honest.
    return Promise.resolve(() => {});
  }
}
