import type { ProviderConfig } from "./providers";
import {
  AUTH_HEADER_X_API_KEY,
  DEFAULT_OPENAI_UPSTREAM,
  DEFAULT_UPSTREAM,
  HEADER_AUTHORIZATION,
  HEADER_HOST,
  HEADER_X_API_KEY,
  PATH_CHAT_COMPLETIONS,
  PATH_V1_CHAT_COMPLETIONS,
} from "./constants";

export type ApiRoute = {
  apiPath: string;
  endpointPath: string;
  isChatCompletions: boolean;
  normalizedPath: string;
};

/**
 * Describes the protocol implied by the client-facing path.
 *
 * The path is the source of truth for request/response format. ProviderConfig.format
 * is only a fallback for old provider records that do not have a format-specific URL.
 */
export function describeApiRoute(apiPath: string): ApiRoute {
  const endpointPath = apiPath.split("?")[0] ?? "";
  const isChatCompletions =
    endpointPath === PATH_CHAT_COMPLETIONS || endpointPath === PATH_V1_CHAT_COMPLETIONS;
  const normalizedPath =
    isChatCompletions && !apiPath.startsWith("/v1/") ? `/v1${apiPath}` : apiPath;

  return { apiPath, endpointPath, isChatCompletions, normalizedPath };
}

export function getProxyApiPath(url: URL): string {
  return url.pathname.replace(/^\/proxy/, "") + url.search;
}

export function selectUpstreamBase(route: ApiRoute, provider: ProviderConfig | null): string {
  if (provider === null) {
    return route.isChatCompletions ? DEFAULT_OPENAI_UPSTREAM : DEFAULT_UPSTREAM;
  }

  const formatSpecificUrl = route.isChatCompletions
    ? provider.openaiBaseUrl
    : provider.anthropicBaseUrl;
  if (formatSpecificUrl !== undefined && formatSpecificUrl !== "") {
    return formatSpecificUrl;
  }
  if (provider.baseUrl !== undefined && provider.baseUrl !== "") {
    return provider.baseUrl;
  }

  // Legacy records may only contain format. Keep this fallback for compatibility,
  // but never use it to infer the response parser; that decision comes from the path.
  return provider.format === "openai" ? DEFAULT_OPENAI_UPSTREAM : DEFAULT_UPSTREAM;
}

export function buildUpstreamUrl(upstreamBase: string, normalizedPath: string): string {
  const base = upstreamBase.endsWith("/") ? upstreamBase.slice(0, -1) : upstreamBase;

  // Many OpenAI-compatible base URLs already include /v1. Avoid producing /v1/v1.
  if (base.endsWith("/v1") && normalizedPath.startsWith("/v1/")) {
    return base + normalizedPath.slice(3);
  }
  return base + normalizedPath;
}

export function setUpstreamHost(headers: Headers, upstreamBase: string): void {
  try {
    headers.set(HEADER_HOST, new URL(upstreamBase).host);
  } catch {
    // Invalid provider URLs are rejected by the UI. Retain the historical default
    // for imported or manually edited config that bypassed that validation.
    headers.set(HEADER_HOST, "api.anthropic.com");
  }
}

export function injectProviderAuth(headers: Headers, provider: ProviderConfig | null): void {
  if (provider === null) return;

  const apiKey = provider.apiKey.replace(/^Bearer\s+/i, "").trim();
  if (provider.authHeader === AUTH_HEADER_X_API_KEY) {
    headers.set(HEADER_X_API_KEY, apiKey);
    headers.delete(HEADER_AUTHORIZATION);
    return;
  }
  headers.set(HEADER_AUTHORIZATION, `Bearer ${apiKey}`);
}
