import { createAnthropic } from '@ai-sdk/anthropic';
import { createAzure } from '@ai-sdk/azure';
import { createDeepSeek } from '@ai-sdk/deepseek';
import { createGoogleGenerativeAI } from '@ai-sdk/google';
import { createMistral } from '@ai-sdk/mistral';
import { createOpenAI } from '@ai-sdk/openai';
import { createXai } from '@ai-sdk/xai';
import { createOpenRouter } from '@openrouter/ai-sdk-provider';
import { createOllama } from 'ollama-ai-provider-v2';

// src/model-factory.ts
var BUILT_IN_PROVIDERS = [
  "anthropic",
  "openai",
  "azure",
  "deepseek",
  "google",
  "ollama",
  "mistral",
  "openrouter",
  "xai"
];
function parseLLMString(llmString, customProviderNames) {
  const parts = llmString.split("/");
  if (parts.length < 2) {
    throw new Error(
      `Invalid LLM string format: "${llmString}". Expected format: "provider/model" (e.g., "openai/gpt-4o")`
    );
  }
  const providerName = parts[0];
  const model = parts.slice(1).join("/");
  if (BUILT_IN_PROVIDERS.includes(providerName)) {
    return {
      type: "builtin",
      provider: providerName,
      model
    };
  }
  if (customProviderNames?.has(providerName)) {
    return {
      type: "custom",
      providerName,
      model
    };
  }
  const allProviders = customProviderNames ? [...BUILT_IN_PROVIDERS, ...customProviderNames] : BUILT_IN_PROVIDERS;
  throw new Error(
    `Unknown LLM provider: "${providerName}". Supported providers: ${allProviders.join(", ")}`
  );
}
function createModelFromCustomProvider(customProvider, model, runtimeApiKey) {
  const apiKey = runtimeApiKey || customProvider.apiKey || (customProvider.apiKeyEnvVar ? process.env[customProvider.apiKeyEnvVar] : void 0) || "";
  switch (customProvider.protocol) {
    case "openai-compatible": {
      const openai = createOpenAI({
        apiKey,
        baseURL: customProvider.baseUrl
      });
      return customProvider.useChatCompletions ? openai.chat(model) : openai(model);
    }
    case "anthropic-compatible": {
      const anthropic = createAnthropic({
        apiKey,
        baseURL: customProvider.baseUrl
      });
      return anthropic(model);
    }
    default: {
      const _exhaustiveCheck = customProvider.protocol;
      throw new Error(`Unknown protocol: ${_exhaustiveCheck}`);
    }
  }
}
function createModelFromString(llmString, options) {
  const { apiKey, baseUrls, customProviders } = options;
  const customProvidersMap = customProviders instanceof Map ? customProviders : customProviders ? new Map(Object.entries(customProviders)) : /* @__PURE__ */ new Map();
  const customProviderNames = new Set(customProvidersMap.keys());
  const parsed = parseLLMString(llmString, customProviderNames);
  if (parsed.type === "custom") {
    const customProvider = customProvidersMap.get(parsed.providerName);
    if (!customProvider) {
      throw new Error(
        `Custom provider "${parsed.providerName}" not found in registry`
      );
    }
    return createModelFromCustomProvider(customProvider, parsed.model, apiKey);
  }
  const { provider, model } = parsed;
  switch (provider) {
    case "anthropic": {
      const anthropic = createAnthropic({
        apiKey,
        ...baseUrls?.anthropic && { baseURL: baseUrls.anthropic }
      });
      return anthropic(model);
    }
    case "openai": {
      const openai = createOpenAI({
        apiKey,
        ...baseUrls?.openai && { baseURL: baseUrls.openai }
      });
      return openai(model);
    }
    case "deepseek": {
      const deepseek = createDeepSeek({ apiKey });
      return deepseek(model);
    }
    case "google": {
      const google = createGoogleGenerativeAI({ apiKey });
      return google(model);
    }
    case "ollama": {
      const raw = baseUrls?.ollama || "http://127.0.0.1:11434/api";
      const normalized = /\/api\/?$/.test(raw) ? raw : `${raw.replace(/\/+$/, "")}/api`;
      const ollama = createOllama({ baseURL: normalized });
      return ollama(model);
    }
    case "mistral": {
      const mistral = createMistral({ apiKey });
      return mistral(model);
    }
    case "openrouter": {
      const openrouter = createOpenRouter({ apiKey });
      return openrouter(model);
    }
    case "xai": {
      const xai = createXai({ apiKey });
      return xai(model);
    }
    case "azure": {
      const azure = createAzure({
        apiKey,
        baseURL: baseUrls?.azure
      });
      return azure(model);
    }
    default: {
      const _exhaustiveCheck = provider;
      throw new Error(`Unhandled provider: ${_exhaustiveCheck}`);
    }
  }
}
function parseModelIds(modelIdsString) {
  return modelIdsString.split(",").map((id) => id.trim()).filter((id) => id.length > 0);
}
function createCustomProvider(config) {
  const modelIds = Array.isArray(config.modelIds) ? config.modelIds : parseModelIds(config.modelIds);
  if (modelIds.length === 0) {
    throw new Error("At least one model ID is required");
  }
  if (!config.name || config.name.includes("/")) {
    throw new Error("Provider name is required and cannot contain '/'");
  }
  if (!config.baseUrl) {
    throw new Error("Base URL is required");
  }
  return {
    name: config.name,
    protocol: config.protocol,
    baseUrl: config.baseUrl,
    modelIds,
    ...config.apiKey && { apiKey: config.apiKey },
    ...config.apiKeyEnvVar && { apiKeyEnvVar: config.apiKeyEnvVar },
    ...config.useChatCompletions && {
      useChatCompletions: config.useChatCompletions
    }
  };
}
var PROVIDER_PRESETS = {
  /** LiteLLM proxy - requires useChatCompletions */
  litellm: (baseUrl = "http://localhost:4000", modelIds) => ({
    name: "litellm",
    protocol: "openai-compatible",
    baseUrl,
    modelIds,
    apiKeyEnvVar: "LITELLM_API_KEY",
    useChatCompletions: true
  })
};
var OrgProviderConfigError = class extends Error {
  code;
  constructor(code, message) {
    super(message);
    this.code = code;
    this.name = "OrgProviderConfigError";
  }
};
function requireOrgSecret(config, label) {
  if (!config.apiKey) {
    throw new OrgProviderConfigError(
      "provider_not_configured",
      `${label} provider has no API key configured for this organization`
    );
  }
  return config.apiKey;
}
function requireOrgBaseUrl(config, label) {
  if (!config.baseUrl) {
    throw new OrgProviderConfigError(
      "provider_not_configured",
      `${label} provider has no base URL configured for this organization`
    );
  }
  return config.baseUrl;
}
function resolveOrgModelId(config, modelId) {
  if (!config.providerKey.startsWith("custom:")) return modelId;
  const prefix = `${config.providerKey}:`;
  return modelId.startsWith(prefix) ? modelId.slice(prefix.length) : modelId;
}
function buildOrgModelFromResolvedConfig(config, modelId) {
  const { providerKey } = config;
  const builtinPfx = `${providerKey}/`;
  const m = !providerKey.startsWith("custom:") && modelId.startsWith(builtinPfx) ? modelId.slice(builtinPfx.length) : modelId;
  if (providerKey === "openai") {
    return createOpenAI({ apiKey: requireOrgSecret(config, "OpenAI") })(m);
  }
  if (providerKey === "anthropic") {
    return createAnthropic({
      apiKey: requireOrgSecret(config, "Anthropic")
    })(m);
  }
  if (providerKey === "google") {
    return createGoogleGenerativeAI({
      apiKey: requireOrgSecret(config, "Google")
    })(m);
  }
  if (providerKey === "deepseek") {
    return createDeepSeek({
      apiKey: requireOrgSecret(config, "DeepSeek")
    })(m);
  }
  if (providerKey === "mistral") {
    return createMistral({
      apiKey: requireOrgSecret(config, "Mistral")
    })(m);
  }
  if (providerKey === "xai") {
    return createXai({ apiKey: requireOrgSecret(config, "xAI") })(
      m
    );
  }
  if (providerKey === "azure") {
    const apiKey = requireOrgSecret(config, "Azure OpenAI");
    const baseUrl = requireOrgBaseUrl(config, "Azure OpenAI");
    const resourceMatch = baseUrl.match(
      /https?:\/\/([^.]+)\.(openai|cognitiveservices)\.azure\.com/i
    );
    const resourceName = resourceMatch?.[1];
    return createAzure({
      apiKey,
      ...resourceName ? { resourceName } : { baseURL: baseUrl }
    })(m);
  }
  if (providerKey === "openrouter") {
    return createOpenRouter({
      apiKey: requireOrgSecret(config, "OpenRouter"),
      headers: {
        "HTTP-Referer": "https://www.mcpjam.com/",
        "X-Title": "MCPJam"
      }
    })(m);
  }
  if (providerKey === "ollama") {
    const raw = requireOrgBaseUrl(config, "Ollama");
    const normalized = /\/api\/?$/.test(raw) ? raw : `${raw.replace(/\/+$/, "")}/api`;
    return createOllama({
      baseURL: normalized
    })(m);
  }
  if (providerKey.startsWith("custom:")) {
    const baseUrl = requireOrgBaseUrl(config, providerKey);
    const apiKey = config.apiKey ?? "";
    const resolvedModelId = resolveOrgModelId(config, modelId);
    if (config.protocol === "anthropic-compatible") {
      return createAnthropic({
        apiKey,
        baseURL: baseUrl
      })(resolvedModelId);
    }
    const openai = createOpenAI({ apiKey, baseURL: baseUrl });
    return openai.chat(resolvedModelId);
  }
  throw new OrgProviderConfigError(
    "provider_not_supported",
    `Provider ${providerKey} is not supported`
  );
}
function assertOrgModelAllowed(config, modelId) {
  if (config.providerKey === "openrouter") {
    if (config.selectedModels && config.selectedModels.length > 0) {
      if (!config.selectedModels.includes(modelId)) {
        throw new OrgProviderConfigError(
          "model_not_allowed",
          `Model ${modelId} is not in this organization's OpenRouter allowlist`
        );
      }
    }
    return;
  }
  if (config.providerKey.startsWith("custom:")) {
    const resolvedModelId = resolveOrgModelId(config, modelId);
    if (config.modelIds && config.modelIds.length > 0) {
      if (!config.modelIds.includes(resolvedModelId)) {
        throw new OrgProviderConfigError(
          "model_not_allowed",
          `Model ${resolvedModelId} is not configured for custom provider ${config.providerKey}`
        );
      }
    }
  }
}

export { OrgProviderConfigError, PROVIDER_PRESETS, assertOrgModelAllowed, buildOrgModelFromResolvedConfig, createCustomProvider, createModelFromString, parseLLMString, parseModelIds };
//# sourceMappingURL=model-factory.js.map
//# sourceMappingURL=model-factory.js.map