import {
  createContext,
  useContext,
  useEffect,
  useState,
  type ReactNode,
} from "react";

import { apiFetch } from "../api";

export type LabeledModel = { value: string; label: string };
export type ThinkingLevelOption = { value: string; label: string };

/** Video model entry; `supports_reference_images` / `supports_4k` / `supports_end_frame` default to true if omitted. */
export type VideoModelOption = {
  value: string;
  label: string;
  supports_reference_images?: boolean;
  supports_4k?: boolean;
  /** Start/end mode: if false, only start frame (e.g. Veo 3 family). */
  supports_end_frame?: boolean;
};

export type GenerationOptions = {
  image: {
    models: LabeledModel[];
    aspect_ratios: string[];
    resolutions: string[];
    /** @deprecated No longer used by the UI; image model + thinking are combined in ImageGen. */
    thinking_levels?: ThinkingLevelOption[];
  };
  video: {
    models: VideoModelOption[];
    aspect_ratios: string[];
    resolutions: string[];
    durations_seconds: number[];
  };
  video_frames: {
    models: VideoModelOption[];
    aspect_ratios: string[];
    resolutions: string[];
    durations_seconds: number[];
  };
};

const GenerationOptionsContext = createContext<GenerationOptions | null>(null);

export function GenerationOptionsProvider({ children }: { children: ReactNode }) {
  const [data, setData] = useState<GenerationOptions | null>(null);
  const [err, setErr] = useState<string | null>(null);

  useEffect(() => {
    let cancelled = false;
    apiFetch("/api/config/generation-options")
      .then(async (r) => {
        if (r.status === 401) {
          window.location.assign("/login");
          return null;
        }
        const j = await r.json().catch(() => ({}));
        if (!r.ok) {
          const detail = (j as { detail?: unknown }).detail;
          const msg =
            typeof detail === "string"
              ? detail
              : Array.isArray(detail)
                ? JSON.stringify(detail)
                : r.statusText;
          throw new Error(msg);
        }
        return j as GenerationOptions;
      })
      .then((opts) => {
        if (cancelled || opts === null) return;
        setData(opts);
      })
      .catch((e: unknown) => {
        if (!cancelled)
          setErr(e instanceof Error ? e.message : "Failed to load options");
      });
    return () => {
      cancelled = true;
    };
  }, []);

  if (err) {
    return (
      <div className="p-8 text-sm text-red-800">
        页面暂时打不开，请稍后再试。
        {err ? (
          <span className="block mt-2 text-xs text-mist">（{err}）</span>
        ) : null}
      </div>
    );
  }

  if (!data) {
    return (
      <div className="p-8 text-sm text-mist">加载中…</div>
    );
  }

  return (
    <GenerationOptionsContext.Provider value={data}>
      {children}
    </GenerationOptionsContext.Provider>
  );
}

const FAST_MODEL_IDS = new Set([
  "gemini-3.1-flash-image-preview",
  "veo-3.0-fast-generate-001",
  "veo-3.1-fast-generate-preview",
]);

/** Prefer Flash/Fast id, else label 快速, else first or `fallback`. */
export function defaultFastModelValue(
  models: { value: string; label?: string }[],
  fallback: string,
): string {
  const byId = models.find((m) => FAST_MODEL_IDS.has(m.value));
  if (byId) return byId.value;
  const byLabel = models.find((m) => m.label?.includes("快速"));
  return byLabel?.value ?? models[0]?.value ?? fallback;
}

export function modelSupportsReferenceImages(
  models: VideoModelOption[],
  value: string,
): boolean {
  const m = models.find((x) => x.value === value);
  return m?.supports_reference_images !== false;
}

export function modelSupports4k(models: VideoModelOption[], value: string): boolean {
  const m = models.find((x) => x.value === value);
  return m?.supports_4k !== false;
}

export function modelSupportsEndFrame(models: VideoModelOption[], value: string): boolean {
  const m = models.find((x) => x.value === value);
  return m?.supports_end_frame !== false;
}

export function useGenerationOptions(): GenerationOptions {
  const ctx = useContext(GenerationOptionsContext);
  if (!ctx) {
    throw new Error("useGenerationOptions must be used inside GenerationOptionsProvider");
  }
  return ctx;
}
