1import type { ProviderInstanceId, UnifiedSettings } from "@t3tools/contracts";
2import { useCallback } from "react";
3
4import { mergeEnvironmentSettings } from "../../hooks/useSettings";
5import { getCustomModelOptionsByInstance } from "../../modelSelection";
6import {
7 applyProviderInstanceSettings,
8 deriveProviderInstanceEntries,
9 type ProviderInstanceEntry,
10} from "../../providerInstances";
11import { useEnvironments } from "../../state/environments";
12import { useSettingsScope } from "./SettingsScopeContext";
13
14/**
15 * A model choice fans out to every selected target, so it must exist on all
16 * of them. Returns the reason a (instance, model) pair cannot be applied, or
17 * null when every target can honor it. The representative's entries decide
18 * which driver the instance id names.
19 */
20export function useScopedModelDisabledReason(
21 settings: UnifiedSettings,
22 entries: readonly ProviderInstanceEntry[],
23) {
24 const { targets } = useSettingsScope();
25 const { environments } = useEnvironments();
26 return useCallback(
27 (instanceId: ProviderInstanceId, model: string): string | null => {
28 const sourceEntry = entries.find((entry) => entry.instanceId === instanceId);
29 for (const candidate of targets) {
30 const environment = environments.find(
31 (entry) => entry.environmentId === candidate.environmentId,
32 );
33 const config = environment?.serverConfig;
34 if (!config) continue;
35 const entry = applyProviderInstanceSettings(
36 deriveProviderInstanceEntries(config.providers),
37 candidate.settings,
38 candidate.projectId,
39 ).find((option) => option.instanceId === instanceId);
40 const options = getCustomModelOptionsByInstance(
41 mergeEnvironmentSettings(candidate.settings, settings),
42 config.providers,
43 ).get(instanceId);
44 if (
45 !entry?.enabled ||
46 !entry.isAvailable ||
47 entry.driverKind !== sourceEntry?.driverKind ||
48 !options?.some((option) => option.slug === model && !option.isUnavailable)
49 ) {
50 return `This model is unavailable on ${environment?.label ?? "a selected environment"}. Select that environment to choose its model separately.`;
51 }
52 }
53 return null;
54 },
55 [entries, environments, settings, targets],
56 );
57}