import { useEffect, useMemo, useState } from "react";

import { api } from "../services/api/client";
import type { ProviderProfile, ProviderProfileStatusItem } from "../types/domain";

export interface ProviderProfileOption {
  value: ProviderProfile;
  label: string;
  configured?: boolean;
}

export const builtinProviderProfileOrder: readonly ProviderProfile[] = Object.freeze(["deepseek", "dsflash-go", "codex-api", "minimax-m3"]);

const builtinProviderProfileLabels: Readonly<Record<string, string>> = Object.freeze({
  deepseek: "DeepSeek",
  "dsflash-go": "DeepSeek V4 Flash",
  "codex-api": "Codex API",
  "minimax-m3": "MiniMax-M3"
});

export function providerProfileLabel(profile: ProviderProfile): string {
  return builtinProviderProfileLabels[profile] ?? profile;
}

export function useProviderProfileOptions(selectedProfile: ProviderProfile): { options: ProviderProfileOption[] } {
  const [options, setOptions] = useState<ProviderProfileOption[]>(() => defaultProviderProfileOptions(selectedProfile));

  useEffect(() => {
    let cancelled = false;
    void (async () => {
      const response = await api.providerProfileCatalog();
      if (cancelled) return;
      if (!response.ok) {
        setOptions(defaultProviderProfileOptions(selectedProfile));
        return;
      }
      const items = profileItems(response.data);
      setOptions(items.length > 0 ? optionsFromItems(items, selectedProfile) : defaultProviderProfileOptions(selectedProfile));
    })();
    return () => {
      cancelled = true;
    };
  }, [selectedProfile]);

  const normalized = useMemo(() => ensureSelectedProfile(options, selectedProfile), [options, selectedProfile]);
  return { options: normalized };
}

function profileItems(payload: unknown): ProviderProfileStatusItem[] {
  const record = payload && typeof payload === "object" ? payload as { items?: ProviderProfileStatusItem[]; data?: { items?: ProviderProfileStatusItem[] } } : {};
  return Array.isArray(record.items) ? record.items : Array.isArray(record.data?.items) ? record.data.items : [];
}

function optionsFromItems(items: ProviderProfileStatusItem[], selectedProfile: ProviderProfile): ProviderProfileOption[] {
  const ordered = [...items]
    .filter((item) => typeof item.profile === "string" && item.profile.trim().length > 0)
    .sort((left, right) => compareProviderProfiles(left.profile, right.profile))
    .map((item) => ({ value: item.profile, label: providerProfileLabel(item.profile), configured: item.configured } satisfies ProviderProfileOption));
  return ensureSelectedProfile(uniqueOptions(ordered), selectedProfile);
}

function defaultProviderProfileOptions(selectedProfile: ProviderProfile): ProviderProfileOption[] {
  const base = builtinProviderProfileOrder.map((profile) => ({ value: profile, label: providerProfileLabel(profile) } satisfies ProviderProfileOption));
  return ensureSelectedProfile(base, selectedProfile);
}

function ensureSelectedProfile(options: ProviderProfileOption[], selectedProfile: ProviderProfile): ProviderProfileOption[] {
  const normalized = String(selectedProfile ?? "").trim();
  if (!normalized) return uniqueOptions(options);
  if (options.some((option) => option.value === normalized)) return uniqueOptions(options);
  return uniqueOptions([{ value: normalized, label: providerProfileLabel(normalized) }, ...options]);
}

function uniqueOptions(options: ProviderProfileOption[]): ProviderProfileOption[] {
  const seen = new Set<string>();
  const result: ProviderProfileOption[] = [];
  for (const option of options) {
    const value = String(option.value ?? "").trim();
    if (!value || seen.has(value)) continue;
    seen.add(value);
    result.push({ ...option, value });
  }
  return result;
}

function compareProviderProfiles(left: ProviderProfile, right: ProviderProfile): number {
  const leftIndex = builtinProviderProfileOrder.indexOf(left);
  const rightIndex = builtinProviderProfileOrder.indexOf(right);
  if (leftIndex >= 0 || rightIndex >= 0) {
    if (leftIndex < 0) return 1;
    if (rightIndex < 0) return -1;
    if (leftIndex !== rightIndex) return leftIndex - rightIndex;
  }
  return left.localeCompare(right);
}
