import type { ClientMembership, LauncherUser } from "../../entities/user/types";
import type { Client } from "../../entities/client/types";
import type { Invite } from "../../entities/invite/types";
import type { LauncherData } from "./mockApi";

export interface PublicInviteResponse {
  invite: Pick<Invite, "id" | "email" | "role" | "expiresAt" | "status" | "source" | "sourceWorkspaceName" | "sourceWorkspaceSlug">;
  client: Pick<Client, "id" | "name" | "status">;
  redirectUrl?: string;
  account: {
    exists: boolean;
    email: string;
  };
}

export interface AcceptInviteResponse {
  invite: Invite;
  client: Client;
  user: LauncherUser;
  membership: ClientMembership;
  data: LauncherData;
  redirectUrl?: string;
}

export interface RegisterInviteCommand {
  email: string;
  name: string;
  password: string;
}

export interface RegisterInviteResponse extends AcceptInviteResponse {
  loginUrl: string;
  redirectUrl: string;
  authenticated: boolean;
}

export async function fetchPublicInvite(token: string): Promise<PublicInviteResponse> {
  return requestJson<PublicInviteResponse>(`/api/invites/${encodeURIComponent(token)}`);
}

export async function registerInvite(token: string, command: RegisterInviteCommand): Promise<RegisterInviteResponse> {
  return requestJson<RegisterInviteResponse>(`/api/invites/${encodeURIComponent(token)}/register`, {
    method: "POST",
    body: JSON.stringify(command),
  });
}

export async function acceptInvite(token: string): Promise<AcceptInviteResponse> {
  return requestJson<AcceptInviteResponse>(`/api/invites/${encodeURIComponent(token)}/accept`, {
    method: "POST",
  });
}

async function requestJson<T>(url: string, init: RequestInit = {}): Promise<T> {
  const headers = new Headers(init.headers);

  if (!headers.has("Content-Type")) {
    headers.set("Content-Type", "application/json");
  }

  const response = await fetch(url, {
    ...init,
    headers,
  });

  if (!response.ok) {
    throw new Error(await readErrorMessage(response));
  }

  return (await response.json()) as T;
}

async function readErrorMessage(response: Response) {
  try {
    const payload = (await response.json()) as { error?: string };
    return payload.error ?? response.statusText;
  } catch {
    return response.statusText;
  }
}
