import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { z } from 'zod'
import JSON5 from 'json5'
import * as TOON from '@toon-format/toon'
import { gguf } from '@huggingface/gguf'

// Hugging Face API configuration
const HF_API_URL = 'https://huggingface.co/api'
const { HF_TOKEN } = process.env

// Helper function to convert BigInt to number for JSON serialization
const convertBigIntToNumber = (value: unknown): number | unknown => {
  if (typeof value === 'bigint') {
    return Number(value)
  }
  return value
}

// Extract GGUF metadata from a GGUF file URL with 10s timeout
const extractGGUFMetadata = async (url: string) => {
  const timeoutPromise = new Promise<never>((_, reject) =>
    setTimeout(() => reject(new Error('GGUF metadata extraction timeout')), 10000),
  )

  try {
    const { metadata } = (await Promise.race([gguf(url), timeoutPromise])) as { metadata: any }
    const architecture = metadata['general.architecture']

    const ggufSimplifiedMetadata: Record<string, unknown> = {
      name: metadata['general.name'],
      size_label: metadata['general.size_label'],
      basename: metadata['general.basename'],
      architecture: metadata['general.architecture'],
      file_type: convertBigIntToNumber(metadata['general.file_type']),
      quantization_version: convertBigIntToNumber(metadata['general.quantization_version']),
    }

    if (!architecture) return ggufSimplifiedMetadata

    // Helper to add converted value if defined
    const addIfDefined = (target: Record<string, unknown>, key: string, value: unknown) => {
      if (value !== undefined) target[key] = convertBigIntToNumber(value)
    }

    // Architecture-specific transformer parameters
    addIfDefined(ggufSimplifiedMetadata, 'n_ctx_train', metadata[`${architecture}.context_length`])
    addIfDefined(ggufSimplifiedMetadata, 'n_layer', metadata[`${architecture}.block_count`])
    addIfDefined(ggufSimplifiedMetadata, 'n_embd', metadata[`${architecture}.embedding_length`])
    addIfDefined(ggufSimplifiedMetadata, 'n_head', metadata[`${architecture}.attention.head_count`])
    addIfDefined(
      ggufSimplifiedMetadata,
      'n_head_kv',
      metadata[`${architecture}.attention.head_count_kv`],
    )
    addIfDefined(
      ggufSimplifiedMetadata,
      'n_embd_head_k',
      metadata[`${architecture}.attention.key_length`],
    )
    addIfDefined(
      ggufSimplifiedMetadata,
      'n_embd_head_v',
      metadata[`${architecture}.attention.value_length`],
    )
    addIfDefined(
      ggufSimplifiedMetadata,
      'n_swa',
      metadata[`${architecture}.attention.sliding_window`],
    )

    // SSM (Mamba) parameters for recurrent/hybrid models
    addIfDefined(ggufSimplifiedMetadata, 'ssm_d_conv', metadata[`${architecture}.ssm.conv_kernel`])
    addIfDefined(ggufSimplifiedMetadata, 'ssm_d_state', metadata[`${architecture}.ssm.state_size`])
    addIfDefined(ggufSimplifiedMetadata, 'ssm_d_inner', metadata[`${architecture}.ssm.inner_size`])
    addIfDefined(ggufSimplifiedMetadata, 'ssm_n_group', metadata[`${architecture}.ssm.group_count`])
    addIfDefined(
      ggufSimplifiedMetadata,
      'ssm_dt_rank',
      metadata[`${architecture}.ssm.time_step_rank`],
    )

    // RWKV parameters
    addIfDefined(
      ggufSimplifiedMetadata,
      'rwkv_head_size',
      metadata[`${architecture}.rwkv.head_size`],
    )
    addIfDefined(
      ggufSimplifiedMetadata,
      'rwkv_token_shift_count',
      metadata[`${architecture}.rwkv.token_shift_count`],
    )

    return ggufSimplifiedMetadata
  } catch (error) {
    console.error('Failed to extract GGUF metadata:', error)
    return null
  }
}

type HFSibling = {
  rfilename: string
  size?: number
  lfs?: { sha256?: string }
  blobId?: string
}

type HFModel = {
  id: string
  author?: string
  downloads?: number
  likes?: number
  tags?: string[]
  pipeline_tag?: string
  siblings?: HFSibling[]
  config?: { model_type?: string }
  cardData?: { model_type?: string }
}

const supportedLlmTasks = [
  'text-generation',
  'image-text-to-text',
  'text2text-generation',
  'conversational',
]

type GeneratorType =
  | 'GeneratorLLM'
  | 'GeneratorVectorStore'
  | 'GeneratorReranker'
  | 'GeneratorGGMLTTS'
  | 'GeneratorGGMLTTSVocoder'
  | 'GeneratorOnnxLLM'
  | 'GeneratorOnnxSTT'
  | 'GeneratorTTS'
  | 'GeneratorMlxLLM'

type ModelKind = 'gguf' | 'onnx' | 'mlx'

interface GeneratorConfig {
  modelKind: ModelKind
  filter: string
  taskFilter?: string[]
  filePattern?: RegExp
  hasValidStructure?: (siblings: HFSibling[]) => boolean
}

// Helper to check valid ONNX structure
const hasValidOnnxStructure = (siblings: HFSibling[]): boolean => {
  const hasConfigJson = siblings.some((file) => file.rfilename === 'config.json')
  const hasOnnxModel = siblings.some(
    (file) => file.rfilename.includes('onnx/') && file.rfilename.endsWith('.onnx'),
  )
  return hasConfigJson && hasOnnxModel
}

// Detect quantization types from ONNX files
const detectOnnxQuantizationTypes = (siblings: HFSibling[]): string[] => {
  const onnxFiles = siblings.filter((file) => file.rfilename.endsWith('.onnx'))
  const quantTypes = new Set<string>()

  onnxFiles.forEach((file) => {
    const filename = file.rfilename
    if (!filename.endsWith('.onnx')) return
    const postfix = /_(q8|q4|q4f16|fp16|int8|int4|uint8|bnb4|quantized)\.onnx$/.exec(filename)?.[1]
    if (!postfix) {
      quantTypes.add('auto')
      quantTypes.add('none')
    } else {
      quantTypes.add(postfix === 'quantized' ? 'q8' : postfix)
    }
  })

  return Array.from(quantTypes)
}

// Find speaker embedding files for TTS models
const findSpeakerEmbedFiles = (siblings: HFSibling[]): HFSibling[] =>
  siblings.filter((file) => file.rfilename.startsWith('voices/') && file.rfilename.endsWith('.bin'))

const generatorConfigs: Record<GeneratorType, GeneratorConfig> = {
  GeneratorLLM: {
    modelKind: 'gguf',
    filter: 'gguf',
    taskFilter: supportedLlmTasks,
    filePattern: /\.gguf$/,
  },
  GeneratorVectorStore: {
    modelKind: 'gguf',
    filter: 'gguf',
    filePattern: /\.gguf$/,
  },
  GeneratorReranker: {
    modelKind: 'gguf',
    filter: 'gguf,reranker',
    filePattern: /\.gguf$/,
  },
  GeneratorGGMLTTS: {
    modelKind: 'gguf',
    filter: 'gguf,text-to-speech',
    filePattern: /\.gguf$/,
  },
  GeneratorGGMLTTSVocoder: {
    modelKind: 'gguf',
    filter: 'gguf,feature-extraction',
    filePattern: /\.gguf$/,
  },
  GeneratorOnnxLLM: {
    modelKind: 'onnx',
    filter: 'onnx',
    taskFilter: supportedLlmTasks,
    hasValidStructure: hasValidOnnxStructure,
  },
  GeneratorOnnxSTT: {
    modelKind: 'onnx',
    filter: 'onnx,automatic-speech-recognition',
    hasValidStructure: hasValidOnnxStructure,
  },
  GeneratorTTS: {
    modelKind: 'onnx',
    filter: 'onnx,text-to-speech',
    hasValidStructure: hasValidOnnxStructure,
  },
  GeneratorMlxLLM: {
    modelKind: 'mlx',
    filter: 'mlx',
    taskFilter: supportedLlmTasks,
  },
}

const searchHFModels = async (filter: string, search?: string, limit = 50): Promise<HFModel[]> => {
  const params = new URLSearchParams({
    limit: String(limit),
    full: 'true',
    config: 'true',
    sort: 'likes',
    direction: '-1',
  })
  if (filter) params.set('filter', filter)
  if (search) params.set('search', search)

  const headers: Record<string, string> = {}
  if (HF_TOKEN) {
    headers['Authorization'] = `Bearer ${HF_TOKEN}`
  }

  const response = await fetch(`${HF_API_URL}/models?${params.toString()}`, { headers })
  if (!response.ok) {
    throw new Error(`Hugging Face API error: ${response.status} ${response.statusText}`)
  }
  return response.json()
}

const fetchHFModelDetails = async (modelId: string): Promise<HFModel> => {
  const params = new URLSearchParams({ blobs: 'true' })

  const headers: Record<string, string> = {}
  if (HF_TOKEN) {
    headers['Authorization'] = `Bearer ${HF_TOKEN}`
  }

  const response = await fetch(`${HF_API_URL}/models/${modelId}?${params.toString()}`, { headers })
  if (!response.ok) {
    throw new Error(`Hugging Face API error: ${response.status} ${response.statusText}`)
  }
  return response.json()
}

// Example: Mixtral-8x22B-v0.1.IQ3_XS-00001-of-00005.gguf
const ggufSplitPattern = /-(\d{5})-of-(\d{5})\.gguf$/

export const buildGGUFSplitFiles = (
  filename: string,
  splitTotal: string,
  siblings: HFSibling[],
): HFSibling[] => {
  const siblingByFilename = new Map<string, HFSibling>()
  for (const sibling of siblings) {
    if (!siblingByFilename.has(sibling.rfilename)) siblingByFilename.set(sibling.rfilename, sibling)
  }

  return Array.from({ length: Number(splitTotal) }, (_, i) => {
    const split = String(i + 1).padStart(5, '0')
    const splitRFilename = filename.replace(ggufSplitPattern, `-${split}-of-${splitTotal}.gguf`)
    const sibling = siblingByFilename.get(splitRFilename)
    return {
      rfilename: splitRFilename,
      size: sibling?.size,
      lfs: sibling?.lfs,
    }
  })
}

export function register(server: McpServer) {
  server.tool(
    'huggingface_search',
    {
      generatorType: z
        .enum([
          'GeneratorLLM',
          'GeneratorVectorStore',
          'GeneratorReranker',
          'GeneratorGGMLTTS',
          'GeneratorGGMLTTSVocoder',
          'GeneratorOnnxLLM',
          'GeneratorOnnxSTT',
          'GeneratorTTS',
          'GeneratorMlxLLM',
        ])
        .describe('Generator type to search models for')
        .default('GeneratorLLM'),
      query: z.string().describe('Search keywords for models on Hugging Face').optional(),
      limit: z.number().min(1).max(100).optional().default(20),
      includeFiles: z
        .boolean()
        .optional()
        .default(false)
        .describe('Include list of model files (requires additional API calls)'),
    },
    async ({ generatorType, query, limit, includeFiles }) => {
      try {
        const config = generatorConfigs[generatorType]
        const models = await searchHFModels(config.filter, query, limit)

        // Filter models based on generator configuration
        const filteredModels = models.filter((model) => {
          const modelTags = model.tags || []

          // Check task filter if configured
          if (config.taskFilter && !config.taskFilter.some((t) => modelTags.includes(t))) {
            return false
          }

          // Check structure validation for ONNX models
          if (config.hasValidStructure && model.siblings) {
            if (!config.hasValidStructure(model.siblings)) {
              return false
            }
          }

          return true
        })

        // Build result models
        let results: Array<{
          id: string
          author?: string
          downloads?: number
          likes?: number
          pipeline_tag?: string
          model_type?: string
          model_kind: ModelKind
          files?: Array<{ filename: string; size?: number }>
          quantization_types?: string[]
          speaker_embed_files?: Array<{ filename: string; size?: number }>
        }> = filteredModels.map((model) => ({
          id: model.id,
          author: model.author,
          downloads: model.downloads,
          likes: model.likes,
          pipeline_tag: model.pipeline_tag,
          model_type: model.config?.model_type || model.cardData?.model_type,
          model_kind: config.modelKind,
        }))

        if (includeFiles) {
          results = await Promise.all(
            results.map(async (model) => {
              try {
                const details = await fetchHFModelDetails(model.id)
                const siblings = details.siblings || []

                if (config.modelKind === 'gguf') {
                  const ggufFiles = siblings
                    .filter((file) => config.filePattern?.test(file.rfilename))
                    .map((file) => ({
                      filename: file.rfilename,
                      size: file.size,
                    }))
                  return { ...model, files: ggufFiles }
                } else {
                  // ONNX models
                  const quantTypes = detectOnnxQuantizationTypes(siblings)
                  const speakerFiles =
                    generatorType === 'GeneratorTTS' ? findSpeakerEmbedFiles(siblings) : []

                  return {
                    ...model,
                    quantization_types: quantTypes,
                    ...(speakerFiles.length > 0 && {
                      speaker_embed_files: speakerFiles.map((f) => ({
                        filename: f.rfilename,
                        size: f.size,
                      })),
                    }),
                  }
                }
              } catch {
                return model
              }
            }),
          )
        }

        return {
          content: [
            {
              type: 'text',
              text: TOON.encode({
                count: results.length,
                generatorType,
                modelKind: config.modelKind,
                models: results,
                hf_token_configured: !!HF_TOKEN,
              }),
            },
          ],
        }
      } catch (err: any) {
        return {
          content: [{ type: 'text', text: `Failed to search models: ${err.message}` }],
        }
      }
    },
  )

  server.tool(
    'huggingface_select',
    {
      generatorType: z
        .enum([
          'GeneratorLLM',
          'GeneratorVectorStore',
          'GeneratorReranker',
          'GeneratorGGMLTTS',
          'GeneratorGGMLTTSVocoder',
          'GeneratorOnnxLLM',
          'GeneratorOnnxSTT',
          'GeneratorTTS',
          'GeneratorMlxLLM',
        ])
        .describe('Generator type for model selection')
        .default('GeneratorLLM'),
      // eslint-disable-next-line camelcase
      model_id: z
        .string()
        .describe('Hugging Face model ID (e.g., "unsloth/Llama-3.2-1B-Instruct-GGUF")'),
      filename: z
        .string()
        .describe('Model filename to select (required for GGUF models)')
        .optional(),
      quantize_type: z
        .string()
        .describe('Quantization type for ONNX models (e.g., "q8", "fp16", "auto")')
        .optional()
        .default('auto'),
      speaker_embed_file: z.string().describe('Speaker embedding file for TTS models').optional(),
    },
    // eslint-disable-next-line camelcase
    async ({
      generatorType,
      model_id: modelId,
      filename,
      quantize_type: quantizeType,
      speaker_embed_file: speakerEmbedFile,
    }) => {
      try {
        const config = generatorConfigs[generatorType]
        const details = await fetchHFModelDetails(modelId)
        const siblings = details.siblings || []

        // Handle ONNX models
        // ONNX generators expect: model (HF model ID), modelType, quantizeType
        if (config.modelKind === 'onnx') {
          const quantTypes = detectOnnxQuantizationTypes(siblings)
          const speakerFiles =
            generatorType === 'GeneratorTTS' ? findSpeakerEmbedFiles(siblings) : []
          const selectedSpeakerFile = speakerEmbedFile
            ? siblings.find((f) => f.rfilename === speakerEmbedFile)
            : undefined

          const selectedQuantType = quantTypes.includes(quantizeType || 'auto')
            ? quantizeType
            : 'auto'
          const modelType = details.config?.model_type || details.cardData?.model_type

          // Result format matches ONNX generator property names (camelCase)
          const result = {
            // Primary model fields for generator
            model: modelId,
            modelType,
            quantizeType: selectedQuantType,
            // Speaker embedding for TTS generators
            ...(selectedSpeakerFile && {
              speakerEmbedUrl: `https://huggingface.co/${modelId}/resolve/main/${selectedSpeakerFile.rfilename}?download=true`,
              speakerEmbedHash: selectedSpeakerFile.lfs?.sha256,
              speakerEmbedHashType: 'sha256',
            }),
            // Additional info
            availableQuantizeTypes: quantTypes,
            ...(speakerFiles.length > 0 && {
              availableSpeakerEmbedFiles: speakerFiles.map((f) => f.rfilename),
            }),
            _hfRepoInfo: {
              repo: modelId,
              model: {
                id: details.id,
                downloads: details.downloads,
                likes: details.likes,
                author: details.author,
              },
              generatorType,
              modelType,
              quantizeType: selectedQuantType,
              ...(selectedSpeakerFile && {
                speakerEmbedFile: selectedSpeakerFile.rfilename,
              }),
            },
          }

          // Return JSON for huggingface_select to allow direct parsing by consumers
          return {
            content: [
              {
                type: 'text',
                text: `${JSON5.stringify(result, null, 2)} // Please use _hfRepoInfo undocumented field with @ts-ignore`,
              },
            ],
          }
        }

        // Handle MLX models (repo-level, like ONNX)
        if (config.modelKind === 'mlx') {
          // Fetch config.json for model architecture metadata
          const headers: Record<string, string> = {}
          if (HF_TOKEN) headers['Authorization'] = `Bearer ${HF_TOKEN}`
          let mlxModelConfig: Record<string, any> | null = null
          try {
            const configRes = await fetch(
              `https://huggingface.co/${modelId}/resolve/main/config.json`,
              { headers },
            )
            if (configRes.ok) mlxModelConfig = await configRes.json()
          } catch {
            // Non-critical
          }

          const modelType =
            mlxModelConfig?.model_type || details.config?.model_type || details.cardData?.model_type

          // Build MLX model metadata from config.json (for hardware guardrails)
          const cfg = mlxModelConfig || ({} as Record<string, any>)
          const textCfg = cfg.text_config || cfg
          const numHeads = textCfg.num_attention_heads || textCfg.n_heads || 0
          const hiddenSize = textCfg.hidden_size || textCfg.dim || 0
          const kvLoraRank = textCfg.kv_lora_rank || 0
          const quant = cfg.quantization || cfg.quantization_config || null

          // Sum safetensors/npz file sizes for model weight bytes
          const modelBytes = siblings
            .filter((f) => /\.(safetensors|npz)$/.test(f.rfilename))
            .reduce((sum, f) => sum + (f.size ?? 0), 0)

          // Build _mlxDownloadFiles list (safetensors, json, jinja, tokenizer.model)
          const mlxDownloadFiles = siblings
            .filter(
              (f) =>
                f.rfilename.endsWith('.safetensors') ||
                f.rfilename.endsWith('.json') ||
                f.rfilename.endsWith('.jinja') ||
                f.rfilename === 'tokenizer.model',
            )
            .map((f) => ({
              url: `https://huggingface.co/${modelId}/resolve/main/${f.rfilename}?download=true`,
              filename: `${modelId.replace('/', '-')}/${f.rfilename}`,
              hash_type: f.lfs ? 'sha256' : f.blobId ? 'sha1' : undefined,
              sha256: f.lfs?.sha256,
              sha1: f.lfs ? undefined : f.blobId,
            }))

          const result = {
            modelId,
            modelType,
            _mlxDownloadFiles: mlxDownloadFiles,
            _hfRepoInfo: {
              repo: modelId,
              model: {
                id: details.id,
                downloads: details.downloads,
                likes: details.likes,
                author: details.author,
              },
              generatorType,
              modelType,
              ...(modelBytes > 0 && { size: modelBytes }),
              ...(mlxModelConfig && {
                mlxModelMetadata: {
                  hiddenSize,
                  numLayers: textCfg.num_hidden_layers || textCfg.n_layers || 0,
                  numHeads,
                  numKvHeads: textCfg.num_key_value_heads ?? numHeads,
                  headDim:
                    textCfg.head_dim ||
                    textCfg.v_head_dim ||
                    (numHeads > 0 && hiddenSize > 0 ? hiddenSize / numHeads : 0),
                  maxCtx: textCfg.max_position_embeddings || 0,
                  kvLoraRank,
                  qkRopeHeadDim: textCfg.qk_rope_head_dim || 0,
                  isMLA: kvLoraRank > 0,
                  quantBits: quant?.bits || null,
                  quantGroupSize: quant?.group_size || null,
                },
              }),
            },
          }

          return {
            content: [
              {
                type: 'text',
                text: `${JSON5.stringify(result, null, 2)} // IMPORTANT: Use _mlxDownloadFiles / _hfRepoInfo undocumented fields with @ts-ignore`,
              },
            ],
          }
        }

        // Handle GGUF models
        if (!filename) {
          // List available GGUF files
          const ggufFiles = siblings
            .filter((file) => config.filePattern?.test(file.rfilename))
            .map((file) => ({
              filename: file.rfilename,
              size: file.size,
            }))

          // Return JSON for huggingface_select to allow direct parsing by consumers
          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify(
                  {
                    error: 'filename is required for GGUF models',
                    available_files: ggufFiles,
                  },
                  null,
                  2,
                ),
              },
            ],
          }
        }

        // Find the selected file
        const selectedFile = siblings.find((f) => f.rfilename === filename)
        if (!selectedFile) {
          return {
            content: [{ type: 'text', text: `File "${filename}" not found in model ${modelId}` }],
          }
        }

        // Check if it's a split file
        const matched = filename.match(ggufSplitPattern)
        const isSplit = !!matched

        // Find mmproj file if available (only for LLM generators)
        const mmprojFile =
          generatorType === 'GeneratorLLM'
            ? siblings.find((f) => /^mmproj-/i.test(f.rfilename))
            : undefined

        // Extract GGUF metadata (for split files, metadata is in the first split)
        const metadataFilename = isSplit
          ? filename.replace(ggufSplitPattern, '-00001-of-$2.gguf')
          : filename
        const ggufUrl = `https://huggingface.co/${modelId}/resolve/main/${metadataFilename}`
        const ggufSimplifiedMetadata = await extractGGUFMetadata(ggufUrl)

        if (isSplit) {
          const [, , splitTotal] = matched!
          const splitFiles = buildGGUFSplitFiles(filename, splitTotal, siblings)

          const first = splitFiles[0]
          const rest = splitFiles.slice(1)

          const result = {
            url: `https://huggingface.co/${modelId}/resolve/main/${first.rfilename}?download=true`,
            hash: first.lfs?.sha256,
            hash_type: 'sha256',
            _ggufSplitFiles: rest.map((split) => ({
              url: `https://huggingface.co/${modelId}/resolve/main/${split.rfilename}?download=true`,
              hash: split.lfs?.sha256,
              hash_type: 'sha256',
            })),
            ...(mmprojFile && {
              mmproj_url: `https://huggingface.co/${modelId}/resolve/main/${mmprojFile.rfilename}?download=true`,
              mmproj_hash: mmprojFile.lfs?.sha256,
              mmproj_hash_type: 'sha256',
            }),
            _hfRepoInfo: {
              repo: modelId,
              model: {
                id: details.id,
                downloads: details.downloads,
                likes: details.likes,
                author: details.author,
              },
              generatorType,
              isSplit: true,
              files: splitFiles.map((f) => f.rfilename),
              sizes: splitFiles.map((f) => f.size),
              size: splitFiles.reduce((acc, f) => acc + (f.size ?? 0), 0),
              ...(mmprojFile && {
                mmprojFile: mmprojFile.rfilename,
                mmprojSize: mmprojFile.size,
              }),
              ...(ggufSimplifiedMetadata && { ggufSimplifiedMetadata }),
            },
          }

          // Return JSON for huggingface_select to allow direct parsing by consumers
          return {
            content: [{ type: 'text', text: JSON5.stringify(result, null, 2) }],
          }
        } else {
          const result = {
            url: `https://huggingface.co/${modelId}/resolve/main/${filename}?download=true`,
            hash: selectedFile.lfs?.sha256,
            hash_type: 'sha256',
            ...(mmprojFile && {
              mmproj_url: `https://huggingface.co/${modelId}/resolve/main/${mmprojFile.rfilename}?download=true`,
              mmproj_hash: mmprojFile.lfs?.sha256,
              mmproj_hash_type: 'sha256',
            }),
            _hfRepoInfo: {
              repo: modelId,
              model: {
                id: details.id,
                downloads: details.downloads,
                likes: details.likes,
                author: details.author,
              },
              generatorType,
              file: filename,
              size: selectedFile.size,
              ...(mmprojFile && {
                mmprojFile: mmprojFile.rfilename,
                mmprojSize: mmprojFile.size,
              }),
              ...(ggufSimplifiedMetadata && { ggufSimplifiedMetadata }),
            },
          }

          // Return JSON for huggingface_select to allow direct parsing by consumers
          return {
            content: [
              {
                type: 'text',
                text: `${JSON5.stringify(result, null, 2)} // IMPORTANT: Use _hfRepoInfo undocumented field with @ts-ignore`,
              },
            ],
          }
        }
      } catch (err: any) {
        return {
          content: [{ type: 'text', text: `Failed to select model: ${err.message}` }],
        }
      }
    },
  )
}
