import { headers } from "next/headers";
import { cache } from "react";
import createFetchClient from "openapi-fetch";

import { authClient } from "@/lib/auth-client";
import { administers } from "@ghost/permissions";
import { INTERNAL_API_URL } from "@/lib/env";

import type { paths } from "@/lib/api/v1";

/** What the API needs from the browser's request: its cookies, and the client address the proxy put in x-forwarded-for, which Better Auth rate-limits by. */
async function forwardedHeaders(): Promise<Record<string, string>> {
  const incoming = await headers();
  const forwarded: Record<string, string> = {};
  for (const name of ["cookie", "x-forwarded-for"]) {
    const value = incoming.get(name);
    if (value) forwarded[name] = value;
  }
  return forwarded;
}

/** Typed API client for server components. `credentials: "include"` is a browser concept, so the incoming request's cookies are forwarded explicitly. */
export async function createServerClient() {
  return createFetchClient<paths>({
    baseUrl: INTERNAL_API_URL,
    headers: await forwardedHeaders(),
  });
}

/** The signed-in session, read over INTERNAL_API_URL: in Docker the public API origin can be this container's own localhost. */
export async function getServerSession(): Promise<
  typeof authClient.$Infer.Session | null
> {
  const forwarded = await forwardedHeaders();
  if (!forwarded.cookie) return null;

  const res = await fetch(`${INTERNAL_API_URL}/api/auth/get-session`, {
    headers: forwarded,
    cache: "no-store",
  });
  return res.ok ? res.json() : null;
}

/** The viewer's role on a repository, fetched once per render however many components ask. */
export const getViewerRole = cache(async (username: string, slug: string) => {
  const client = await createServerClient();
  const { data } = await client.GET("/api/repositories/{username}/{slug}", {
    params: { path: { username, slug } },
  });
  return data?.viewerRole ?? null;
});

/** Slugs of the organizations the viewer administers, where they may create, fork and transfer repositories to. */
export const getAdminOrganizations = cache(async () => {
  const client = await createServerClient();
  const { data } = await client.GET("/api/organizations");
  return (data?.organizations ?? [])
    .filter((organization) => administers(organization.viewerRole))
    .map((organization) => organization.slug);
});
