import type { WorkbenchApplication, WorkbenchEventPublisher } from "./contracts.ts";
import { normalizeWorkbenchCloudAuthorization } from "./cloud-authorization.ts";

export function createCloudWorkbenchApplication(options: {
  baseUrl: string;
  authorization: string;
  fetchImpl?: typeof fetch;
  eventPublisher?: WorkbenchEventPublisher | null;
}): WorkbenchApplication {
  if (!options.baseUrl) throw codedError("workbench_cloud_api_url_required", "WORKBENCH_CLOUD_API_URL is required");
  const authorization = normalizeWorkbenchCloudAuthorization(options.authorization);
  if (!authorization) throw codedError("workbench_cloud_api_auth_required", "WORKBENCH_CLOUD_API_AUTHORIZATION is required");
  const fetchImpl = options.fetchImpl ?? fetch;
  const request = async (method: string, route: string, body: Record<string, unknown> | undefined, actor: { id: string; role?: string | null }) => {
    const response = await fetchImpl(`${options.baseUrl.replace(/\/$/u, "")}${route}`, {
      method,
      headers: {
        authorization,
        "content-type": "application/json",
        "x-workbench-activity-dispatch": "1",
        "x-hwlab-actor-id": actor.id,
        "x-hwlab-actor-role": actor.role ?? "user"
      },
      body: body ? JSON.stringify(body) : undefined
    });
    const payload = await response.json().catch(() => null) as Record<string, unknown> | null;
    if (!response.ok || !payload) {
      const error = payload?.error && typeof payload.error === "object" ? payload.error as Record<string, unknown> : {};
      throw codedError(String(error.code ?? "workbench_cloud_api_failed"), String(error.message ?? `Cloud API returned ${response.status}`), {
        status: response.status,
        route,
        layer: error.layer,
        retryable: error.retryable,
        userMessage: error.userMessage
      });
    }
    return payload;
  };
  return {
    async health() { return { serviceId: "hwlab-workbench", status: "ready", cloudApi: "configured" }; },
    async createSession(input) { return request("POST", "/v1/agent/sessions", input.params, input.actor); },
    async admitTurn(input) {
      await request("POST", "/v1/internal/workbench/admit", { ...input.params, traceId: input.traceId, sessionId: input.sessionId }, input.actor);
      return input;
    },
    async dispatchTurn(input) {
      return request("POST", "/v1/agent/chat", { ...input.params, traceId: input.traceId, sessionId: input.sessionId, shortConnection: true }, input.actor);
    },
    async cancelTurn(input) {
      return request("POST", "/v1/agent/chat/cancel", { ...input.params, traceId: input.traceId }, input.actor);
    },
    async close() { await options.eventPublisher?.close?.(); }
  };
}

function codedError(code: string, message: string, details: Record<string, unknown> = {}) {
  return Object.assign(new Error(message), {
    code,
    details,
    status: details.status,
    layer: details.layer,
    retryable: details.retryable,
    userMessage: details.userMessage
  });
}
