import useSWR, { type SWRResponse, useSWRConfig } from "swr";
import { fetchJson } from "./apiClient";
import {
  DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS,
  RuntimeConfigSchema,
  type RuntimeConfig,
} from "./runtimeConfig";

export const STRIP_CONFIG_SWR_KEY = "/api/config";

async function fetcher(url: string): Promise<RuntimeConfig> {
  return fetchJson(
    url,
    RuntimeConfigSchema,
    undefined,
    (response) => `Failed to fetch ${url}: ${response.status}`,
  );
}

/**
 * PATCH the runtime config. Exported separately for testability.
 */
export async function setRuntimeConfig(patch: Partial<RuntimeConfig>): Promise<RuntimeConfig> {
  return fetchJson(
    STRIP_CONFIG_SWR_KEY,
    RuntimeConfigSchema,
    {
      method: "PATCH",
      headers: { "content-type": "application/json" },
      body: JSON.stringify(patch),
    },
    (response) => `PATCH failed with status ${response.status}`,
  );
}

export type UseStripConfig = {
  strip: boolean;
  slowResponseThresholdSeconds: number;
  isLoading: boolean;
  isError: boolean;
  setStrip: (next: boolean) => Promise<void>;
  setSlowResponseThresholdSeconds: (next: number) => Promise<void>;
};

/**
 * Hook reading the runtime config from /api/config.
 *
 * - `strip` is the live value from the server (or the optimistic value mid-PATCH).
 * - `slowResponseThresholdSeconds` controls the UI's slow-response indicator.
 * - `setStrip(next)` PATCHes the server with optimistic update; on failure
 *   it throws and SWR rolls back the optimistic value.
 */
export function useStripConfig(): UseStripConfig {
  const response: SWRResponse<RuntimeConfig, Error> = useSWR<RuntimeConfig, Error>(
    STRIP_CONFIG_SWR_KEY,
    fetcher,
    {
      revalidateOnFocus: false,
      revalidateIfStale: false,
    },
  );
  const { mutate: globalMutate } = useSWRConfig();

  const strip = response.data?.stripClaudeCodeBillingHeader ?? false;
  const slowResponseThresholdSeconds =
    response.data?.slowResponseThresholdSeconds ?? DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS;

  const optimisticConfig = (patch: Partial<RuntimeConfig>): RuntimeConfig => ({
    stripClaudeCodeBillingHeader: response.data?.stripClaudeCodeBillingHeader ?? false,
    hasSeenOnboarding: response.data?.hasSeenOnboarding ?? false,
    slowResponseThresholdSeconds:
      response.data?.slowResponseThresholdSeconds ?? DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS,
    ...patch,
  });

  const setStrip = async (next: boolean): Promise<void> => {
    await globalMutate(
      STRIP_CONFIG_SWR_KEY,
      setRuntimeConfig({ stripClaudeCodeBillingHeader: next }),
      {
        optimisticData: optimisticConfig({ stripClaudeCodeBillingHeader: next }),
        rollbackOnError: true,
        revalidate: false,
      },
    );
  };

  const setSlowResponseThresholdSeconds = async (next: number): Promise<void> => {
    await globalMutate(
      STRIP_CONFIG_SWR_KEY,
      setRuntimeConfig({ slowResponseThresholdSeconds: next }),
      {
        optimisticData: optimisticConfig({ slowResponseThresholdSeconds: next }),
        rollbackOnError: true,
        revalidate: false,
      },
    );
  };

  return {
    strip,
    slowResponseThresholdSeconds,
    isLoading: response.isLoading,
    isError: response.error !== undefined,
    setStrip,
    setSlowResponseThresholdSeconds,
  };
}
