// Generated by smithplates HTTP codegen. Do not edit.

import { ClientOperationHttpBinding, variantForStatus, typeNameForStatus } from "generated/example/chatApi/client/operationBindings";
import { parseRoomListOutput as _parse_RoomListOutput } from "generated/example/roomListOutput";
import { parseServerMessage as _parse_ServerMessage } from "generated/example/serverMessage";

/** Normalized fetch/axios response shape consumed by the generated client. */
export interface NormalizedResponse {
  status: number;
  headers: Record<string, string>;
  text(): Promise<string>;
  json(): Promise<unknown>;
}

/** Raised when an HTTP response cannot be mapped to a generated API model. */
export class ClientResponseError extends Error {
  constructor(message: string) {
    super(message);
    this.name = "ClientResponseError";
  }
}

const _MODEL_PARSERS: Record<string, (value: unknown) => unknown> = {
  "RoomListOutput": _parse_RoomListOutput,
  "ServerMessage": _parse_ServerMessage,
};

function _resolveModelParser(typeName: string): (value: unknown) => unknown {
  const parser = _MODEL_PARSERS[typeName];
  if (parser === undefined) {
    throw new ClientResponseError("Unknown generated API model type " + typeName);
  }
  return parser;
}

function _headerValue(response: NormalizedResponse, headerName: string): string | undefined {
  const lower = headerName.toLowerCase();
  const direct = response.headers[headerName];
  if (direct !== undefined) {
    return direct;
  }
  return response.headers[lower];
}

/** Map an HTTP response to a generated API model using Smithy-derived bindings. */
export async function parseClientResponse(
  response: NormalizedResponse,
  binding: ClientOperationHttpBinding,
): Promise<unknown> {
  if (response.status === 204 || binding.variantsByStatus[response.status] === "__empty__") {
    if (response.status >= 400) {
      throw new ClientResponseError("HTTP " + response.status);
    }
    return null;
  }

  const variant = variantForStatus(binding, response.status);
  const typeName = typeNameForStatus(binding, response.status);
  const parse = _resolveModelParser(typeName);

  let payload: Record<string, unknown> = {};
  if (variant.mediaType !== null) {
    const body = await response.json();
    if (body !== null && body !== undefined) {
      if (typeof body === "object" && !Array.isArray(body)) {
        payload = { ...(body as Record<string, unknown>) };
      } else {
        payload = { value: body };
      }
    }
  }

  for (const [memberName, headerName] of variant.headerBindings) {
    const headerValue = _headerValue(response, headerName);
    if (headerValue !== undefined) {
      payload[memberName] = headerValue;
    }
  }

  if (variant.mediaType === null && variant.headerBindings.length === 0) {
    if (response.status >= 400) {
      throw new ClientResponseError("HTTP " + response.status);
    }
    return null;
  }

  if (response.status >= 400) {
    return parse(payload);
  }

  if (Object.keys(payload).length === 0 && variant.mediaType === null) {
    return null;
  }

  return parse(payload);
}
