// The scenario environment as Effect services. A scenario declares what it
// needs by yielding these tags; the requirements surface in its R channel,
// where the compiler checks them against the `needs` list (the same tags as
// runtime values — what drives skip records for targets that lack one).
// Target/RunDir/Cli are always provided; the rest depend on the target's
// capabilities and the host environment.
import { Context, type Effect } from "effect";

import type { Target as TargetShape } from "./target";
import type { ApiSurface } from "./surfaces/api";
import type { AutumnSurface } from "./surfaces/autumn";
import type { BrowserSurface } from "./surfaces/browser";
import type { CliSurface } from "./surfaces/cli";
import type { McpSurface } from "./surfaces/mcp";
import type { TelemetrySurface } from "./surfaces/telemetry";
import type { completeOAuthConsent, makeOpenCodeHome, warmUp } from "./clients/opencode";

/** The target under test (always provided). */
export class Target extends Context.Service<Target, TargetShape>()("e2e/target") {}

/** This run's artifact directory (always provided). */
export class RunDir extends Context.Service<RunDir, string>()("e2e/run-dir") {}

/** Real-PTY terminal sessions with cast recording (always provided — host machinery, not a target trait). */
export class Cli extends Context.Service<Cli, CliSurface>()("e2e/cli") {}

/** Typed HttpApiClient over the wire (target capability "api"). */
export class Api extends Context.Service<Api, ApiSurface>()("e2e/api") {}

/** Playwright browser sessions with video/trace (target capability "browser"). */
export class Browser extends Context.Service<Browser, BrowserSurface>()("e2e/browser") {}

/** MCP client sessions + headless OAuth flows (target capability "mcp-oauth"). */
export class Mcp extends Context.Service<Mcp, McpSurface>()("e2e/mcp-oauth") {}

/** Marker: billing limits are enforced on this target. */
export class Billing extends Context.Service<Billing, true>()("e2e/billing") {}

/** Read the usage events the target tracked to its billing backend (present
 *  when the suite booted the Autumn emulator — E2E_AUTUMN_URL; cloud-only). */
export class Autumn extends Context.Service<Autumn, AutumnSurface>()("e2e/autumn") {}

/** Query the suite's OTLP trace store for spans the target actually exported
 *  (present when the suite booted motel — E2E_MOTEL_URL). */
export class Telemetry extends Context.Service<Telemetry, TelemetrySurface>()("e2e/telemetry") {}

/** The real OpenCode binary, hermetically driveable (present when installed on this host). */
export interface OpenCodeClient {
  readonly makeHome: typeof makeOpenCodeHome;
  readonly warmUp: typeof warmUp;
  readonly completeOAuthConsent: typeof completeOAuthConsent;
}
export class OpenCode extends Context.Service<OpenCode, OpenCodeClient>()("e2e/opencode") {}

/** Compress (or restore, with null) the authorization server's access-token TTL. */
export class TtlControl extends Context.Service<
  TtlControl,
  (seconds: number | null) => Effect.Effect<void>
>()("e2e/ttl-control") {}

/**
 * Restart the instance, keeping its data. What lets durability scenarios
 * assert that writes survive a process restart — the property a dev server
 * with a fresh data dir can never test by accident.
 */
export class Restart extends Context.Service<Restart, () => Effect.Effect<void>>()("e2e/restart") {}
