import {
  Workflow,
  FileCheck2,
  CalendarClock,
  Building2,
  Database,
  DatabaseZap,
  ShoppingBag,
  ClipboardList,
  BrainCircuit,
  Linkedin,
  Home,
  Search,
  Network,
  FileText,
  FilePen,
  Globe,
  ContactRound,
  MessageSquareQuote,
  Mail,
  MessageSquareText,
  MessageCircle,
  MessageSquareDot,
  BotMessageSquare,
  Webhook,
  KeyRound,
  ScanText,
  BrainCog,
  BarChart3,
  Image as ImageIcon,
  Video,
  type LucideIcon,
} from 'lucide-react'
import { summarizeSchedule } from '../../util/schedule'
import { parseResultObject } from '../../util/objectUtils'
import type { ToolCallEntry } from '../agentChat/types'
import type { ToolDescriptor, ToolDescriptorTransform } from '../agentChat/tooling/types'
import { summarizeToolSearchForCaption } from '../agentChat/tooling/searchUtils'
import type { DetailKind } from '../agentChat/toolDetails'
import { extractBrightDataArray, extractBrightDataResultCount, extractBrightDataSearchQuery } from './brightdata'
import { extractSqlStatementsFromParameters } from './sqliteDisplay'

const COMMUNICATION_TOOL_NAMES = [
  'send_email',
  'send_sms',
  'send_web_message',
  'send_chat_message',
  'send_agent_message',
] as const

const BASE_SKIP_TOOL_NAMES = ['sleep', 'sleep_until_next_trigger', 'action', 'update_plan', '', null] as const

export const CHAT_SKIP_TOOL_NAMES = new Set<string | null>([
  ...COMMUNICATION_TOOL_NAMES,
  ...BASE_SKIP_TOOL_NAMES,
])

export const USAGE_SKIP_TOOL_NAMES = new Set<string | null>(BASE_SKIP_TOOL_NAMES)

export const SKIP_TOOL_NAMES = CHAT_SKIP_TOOL_NAMES

const LINKEDIN_ICON_BG_CLASS = 'bg-sky-100'
const LINKEDIN_ICON_COLOR_CLASS = 'text-sky-700'
const TOOL_SEARCH_TOOL_NAMES = new Set(['search_tools', 'search_web', 'web_search', 'search'])

export type ToolMetadataConfig = {
  name: string
  aliases?: string[]
  label: string
  icon: LucideIcon
  iconBgClass: string
  iconColorClass: string
  detailKind: DetailKind
  skip?: boolean
  derive?(entry: ToolCallEntry, parameters: Record<string, unknown> | null): ToolDescriptorTransform | void
}

export function truncate(value: string, max = 60): string {
  if (value.length <= max) return value
  return `${value.slice(0, max - 1)}…`
}

function buildTrailingPreview(value: string, max = 96): string {
  const normalized = value.replace(/\s+/g, ' ').trim()
  if (!normalized) return ''
  const preview = normalized.length >= max
    ? normalized.slice(0, max - 1).trimEnd()
    : normalized
  return `${preview}…`
}

export function coerceString(value: unknown): string | null {
  if (typeof value === 'string' && value.trim().length > 0) {
    return value
  }
  return null
}

function coerceNumber(value: unknown): number | null {
  if (typeof value === 'number' && Number.isFinite(value)) {
    return value
  }
  if (typeof value === 'string') {
    const parsed = Number(value.replace(/[, ]+/g, ''))
    return Number.isFinite(parsed) ? parsed : null
  }
  return null
}

function formatCount(value: number | null): string | null {
  if (value === null) return null
  return value.toLocaleString()
}

function pickFirstParameter(
  parameters: Record<string, unknown> | null | undefined,
  keys: string[],
): string | null {
  if (!parameters) return null
  for (const key of keys) {
    const value = coerceString(parameters[key])
    if (value) {
      return value
    }
  }
  return null
}

function deriveLinkedInCaption(
  parameters: Record<string, unknown> | null | undefined,
  keys: string[],
  fallback?: string | null,
): string | null {
  const value = pickFirstParameter(parameters, keys)
  if (value) {
    return truncate(value, 56)
  }
  return fallback ?? null
}

function firstMeaningfulLine(value: string | null | undefined): string | null {
  if (!value) {
    return null
  }
  const line = value
    .split(/\r?\n/)
    .map((part) => part.trim())
    .find(Boolean)
  return line || null
}

function summarizeCode(value: string | null | undefined, fallback: string, max = 56): string {
  const firstLine = firstMeaningfulLine(value)
  if (firstLine) {
    return truncate(firstLine, max)
  }
  return fallback
}


function deriveFileExport(
  entry: ToolCallEntry,
  parameters: Record<string, unknown> | null,
  fallbackLabel: string,
): ToolDescriptorTransform {
  const resultObject = parseResultObject(entry.result)
  const status = coerceString(resultObject?.['status'])
  const paramPath = coerceString(parameters?.['file_path']) || coerceString(parameters?.['path'])
  const filename = coerceString(resultObject?.['filename']) || paramPath || coerceString(parameters?.['filename'])
  const path = coerceString(resultObject?.['path']) || paramPath
  const isError = status?.toLowerCase() === 'error'

  const caption = path ? truncate(path, 56) : filename ? truncate(filename, 56) : null
  const summaryParts: string[] = []
  if (path) {
    summaryParts.push(path)
  }
  if (filename && filename !== path) {
    summaryParts.push(filename)
  }

  return {
    label: isError ? `${fallbackLabel} failed` : fallbackLabel,
    caption: caption ?? entry.caption ?? fallbackLabel,
    summary: summaryParts.length ? truncate(summaryParts.join(' • '), 96) : entry.summary ?? null,
  }
}

export const TOOL_METADATA_CONFIGS: ToolMetadataConfig[] = [
  {
    name: 'run_command',
    label: 'Run command',
    icon: Workflow,
    iconBgClass: 'bg-slate-100',
    iconColorClass: 'text-slate-700',
    detailKind: 'runCommand',
    derive(entry, parameters) {
      const command = coerceString(parameters?.command)
      const cwd = coerceString(parameters?.cwd)
      const result = parseResultObject(entry.result)
      const status = coerceString(result?.['status'])
      const exitCode = result?.['exit_code']
      const exitLabel =
        typeof exitCode === 'number' || typeof exitCode === 'string'
          ? `exit ${String(exitCode)}`
          : null
      const summary = [cwd ? `cwd ${cwd}` : null, exitLabel].filter(Boolean).join(' • ') || null

      return {
        caption: summarizeCode(command, 'Run command'),
        summary: summary ?? (status && status !== 'ok' ? status : entry.summary ?? null),
      }
    },
  },
  {
    name: 'python_exec',
    label: 'Run Python',
    icon: BrainCog,
    iconBgClass: 'bg-amber-100',
    iconColorClass: 'text-amber-700',
    detailKind: 'pythonExec',
    derive(entry, parameters) {
      const code = coerceString(parameters?.code)
      const timeout = coerceString(parameters?.timeout_seconds)
      const result = parseResultObject(entry.result)
      const exitCode = result?.['exit_code']
      const summaryParts = [
        timeout ? `${timeout}s timeout` : null,
        typeof exitCode === 'number' || typeof exitCode === 'string' ? `exit ${String(exitCode)}` : null,
      ].filter(Boolean)

      return {
        caption: summarizeCode(code, 'Run Python'),
        summary: summaryParts.length ? summaryParts.join(' • ') : entry.summary ?? null,
      }
    },
  },
  {
    name: 'file_str_replace',
    label: 'Replace in file',
    icon: FilePen,
    iconBgClass: 'bg-emerald-100',
    iconColorClass: 'text-emerald-700',
    detailKind: 'fileStringReplace',
    derive(entry, parameters) {
      const path = coerceString(parameters?.path)
      const result = parseResultObject(entry.result)
      const replacements = result?.['replacements']
      const replacementLabel =
        typeof replacements === 'number' || typeof replacements === 'string'
          ? `${String(replacements)} replacement${String(replacements) === '1' ? '' : 's'}`
          : null

      return {
        caption: path ? truncate(path, 56) : 'Replace in file',
        summary: replacementLabel ?? coerceString(result?.['message']) ?? entry.summary ?? null,
      }
    },
  },
  {
    name: 'create_custom_tool',
    label: 'Create tool',
    icon: BotMessageSquare,
    iconBgClass: 'bg-cyan-100',
    iconColorClass: 'text-cyan-700',
    detailKind: 'createCustomTool',
    derive(entry, parameters) {
      const result = parseResultObject(entry.result)
      const toolName = coerceString(result?.['tool_name'])
      const name = coerceString(result?.['name']) || coerceString(parameters?.name)
      const sourcePath = coerceString(result?.['source_path']) || coerceString(parameters?.source_path)
      const message = coerceString(result?.['message'])
      const caption = toolName || name || sourcePath

      return {
        caption: caption ? truncate(caption, 56) : 'Create tool',
        summary: message ?? entry.summary ?? null,
      }
    },
  },
  {
    name: 'update_charter',
    label: 'Assignment updated',
    icon: FileCheck2,
    iconBgClass: 'bg-indigo-100',
    iconColorClass: 'text-indigo-600',
    detailKind: 'updateCharter',
    derive(entry, parameters) {
      const charterText = coerceString(parameters?.new_charter) || coerceString(parameters?.charter) || coerceString(entry.result)
      return {
        charterText,
        caption: charterText ? truncate(charterText, 48) : entry.caption ?? 'Assignment updated',
        separateFromPreview: true,
      }
    },
  },
  {
    name: 'end_planning',
    label: 'Planning completed',
    icon: ClipboardList,
    iconBgClass: 'bg-emerald-100',
    iconColorClass: 'text-emerald-700',
    detailKind: 'endPlanning',
    derive(_entry, parameters) {
      const fullPlan = coerceString(parameters?.full_plan)
      return {
        charterText: fullPlan,
        caption: fullPlan ? buildTrailingPreview(fullPlan) : null,
        summary: null,
      }
    },
  },
  {
    name: 'update_schedule',
    label: 'Schedule updated',
    icon: CalendarClock,
    iconBgClass: 'bg-sky-100',
    iconColorClass: 'text-sky-600',
    detailKind: 'updateSchedule',
    derive(_, parameters) {
      const scheduleValue = coerceString(parameters?.new_schedule)
      const summary = summarizeSchedule(scheduleValue)
      return {
        caption: summary ?? (scheduleValue ? truncate(scheduleValue, 40) : 'Disabled'),
        separateFromPreview: true,
      }
    },
  },
  {
    name: 'sqlite_batch',
    label: 'Database query',
    icon: Database,
    iconBgClass: 'bg-emerald-100',
    iconColorClass: 'text-emerald-600',
    detailKind: 'sqliteBatch',
    derive(_entry, parameters) {
      const statements = extractSqlStatementsFromParameters(parameters)
      return {
        caption: statements.length ? `${statements.length} statement${statements.length === 1 ? '' : 's'}` : 'SQL batch',
        sqlStatements: statements,
      }
    },
  },
  {
    name: 'enable_database',
    label: 'Database enabled',
    icon: DatabaseZap,
    iconBgClass: 'bg-emerald-50',
    iconColorClass: 'text-emerald-600',
    detailKind: 'enableDatabase',
    derive(entry) {
      const resultObject = parseResultObject(entry.result)
      const messageValue = resultObject?.['message']
      const statusValue = resultObject?.['status']
      const managerValue = resultObject?.['tool_manager']

      const message = coerceString(messageValue)
      const status = coerceString(statusValue)
      const manager =
        managerValue && typeof managerValue === 'object' && !Array.isArray(managerValue)
          ? (managerValue as Record<string, unknown>)
          : null

      const toStringList = (value: unknown): string[] => {
        if (!Array.isArray(value)) return []
        return (value as unknown[])
          .map((item) => (typeof item === 'string' && item.trim().length > 0 ? item : null))
          .filter((item): item is string => Boolean(item))
      }

      const enabledList = toStringList(manager?.['enabled'])
      const alreadyEnabledList = toStringList(manager?.['already_enabled'])

      const summaryPieces: string[] = []
      if (status) {
        summaryPieces.push(status === 'ok' ? 'Enabled' : status)
      }
      if (enabledList.length) {
        summaryPieces.push(`Enabled: ${enabledList.join(', ')}`)
      } else if (alreadyEnabledList.length) {
        summaryPieces.push(`Already enabled: ${alreadyEnabledList.join(', ')}`)
      }

      const summaryText = summaryPieces.length ? truncate(summaryPieces.join(' • '), 96) : null
      const label = message && /already/i.test(message) ? 'Database already enabled' : 'Database enabled'

      return {
        label,
        caption: message ? truncate(message, 56) : entry.caption ?? label,
        summary: summaryText ?? message ?? entry.summary ?? null,
      }
    },
  },
  {
    name: 'api_task',
    label: 'API task',
    icon: ClipboardList,
    iconBgClass: 'bg-slate-100',
    iconColorClass: 'text-slate-600',
    detailKind: 'default',
    derive() {
      return {
        caption: 'Agentless task triggered via API',
      }
    },
  },
  {
    name: 'agent_runtime',
    label: 'Agent runtime',
    icon: BrainCircuit,
    iconBgClass: 'bg-slate-100',
    iconColorClass: 'text-slate-600',
    detailKind: 'default',
    derive() {
      return {
        caption: 'Internal agent workflow and reasoning',
      }
    },
  },
  {
    name: 'search_tools',
    aliases: ['search_web', 'web_search', 'search'],
    label: 'Tool search',
    icon: Search,
    iconBgClass: 'bg-blue-100',
    iconColorClass: 'text-blue-600',
    detailKind: 'search',
    derive(entry, parameters) {
      const rawQuery = coerceString(parameters?.query) || coerceString(parameters?.prompt)
      const truncatedQuery = rawQuery ? truncate(rawQuery, 48) : null
      const isToolSearch = TOOL_SEARCH_TOOL_NAMES.has(entry.toolName?.toLowerCase() ?? '')

      if (isToolSearch) {
        const { caption, summary } = summarizeToolSearchForCaption(entry, truncatedQuery)
        const safeCaption = caption ? truncate(caption, 56) : null
        return {
          label: 'Tool search',
          caption: safeCaption ?? (truncatedQuery ? `“${truncatedQuery}”` : 'Tool search'),
          summary,
        }
      }

      const fallbackCaption = truncatedQuery ? `“${truncatedQuery}”` : null
      return {
        label: 'Tool search',
        caption: fallbackCaption ?? 'Search',
      }
    },
  },
  {
    name: 'api_call',
    aliases: ['http_request', 'http'],
    label: 'API request',
    icon: Network,
    iconBgClass: 'bg-cyan-100',
    iconColorClass: 'text-cyan-600',
    detailKind: 'apiRequest',
    derive(_, parameters) {
      const url = coerceString(parameters?.url) || coerceString(parameters?.endpoint)
      const method = coerceString(parameters?.method)
      const captionPieces = [method ? method.toUpperCase() : null, url ? truncate(url, 36) : null].filter(Boolean)
      return {
        caption: captionPieces.length ? captionPieces.join(' • ') : 'API request',
      }
    },
  },
  {
    name: 'read_file',
    aliases: ['file_read'],
    label: 'File access',
    icon: FileText,
    iconBgClass: 'bg-orange-100',
    iconColorClass: 'text-orange-600',
    detailKind: 'fileRead',
    derive(_, parameters) {
      const path = coerceString(parameters?.path) || coerceString(parameters?.file_path) || coerceString(parameters?.filename)
      return { caption: path ? truncate(path, 40) : 'Read file' }
    },
  },
  {
    name: 'create_csv',
    label: 'CSV export',
    icon: ClipboardList,
    iconBgClass: 'bg-emerald-100',
    iconColorClass: 'text-emerald-600',
    detailKind: 'fileExport',
    derive(entry, parameters) {
      return deriveFileExport(entry, parameters, 'CSV export')
    },
  },
  {
    name: 'create_file',
    label: 'File export',
    icon: FileText,
    iconBgClass: 'bg-slate-100',
    iconColorClass: 'text-slate-600',
    detailKind: 'fileExport',
    derive(entry, parameters) {
      return deriveFileExport(entry, parameters, 'File export')
    },
  },
  {
    name: 'create_pdf',
    label: 'PDF export',
    icon: FileText,
    iconBgClass: 'bg-rose-100',
    iconColorClass: 'text-rose-600',
    detailKind: 'fileExport',
    derive(entry, parameters) {
      return deriveFileExport(entry, parameters, 'PDF export')
    },
  },
  {
    name: 'create_chart',
    label: 'Chart',
    icon: BarChart3,
    iconBgClass: 'bg-indigo-100',
    iconColorClass: 'text-indigo-600',
    detailKind: 'chart',
    derive(_entry, parameters) {
      const chartType = coerceString(parameters?.type)
      const title = coerceString(parameters?.title)
      const caption = title || (chartType ? `${chartType} chart` : 'Chart')
      return { caption: truncate(caption, 40) }
    },
  },
  {
    name: 'create_image',
    label: 'Image',
    icon: ImageIcon,
    iconBgClass: 'bg-cyan-100',
    iconColorClass: 'text-cyan-700',
    detailKind: 'image',
    derive(_entry, parameters) {
      const filePath = coerceString(parameters?.file_path) || coerceString(parameters?.path)
      const prompt = coerceString(parameters?.prompt)
      const caption = filePath || prompt || 'Image'
      return { caption: truncate(caption, 56) }
    },
  },
  {
    name: 'create_video',
    label: 'Video',
    icon: Video,
    iconBgClass: 'bg-rose-100',
    iconColorClass: 'text-rose-700',
    detailKind: 'video',
    derive(_entry, parameters) {
      const filePath = coerceString(parameters?.file_path) || coerceString(parameters?.path)
      const prompt = coerceString(parameters?.prompt)
      const caption = filePath || prompt || 'Video'
      return { caption: truncate(caption, 56) }
    },
  },
  {
    name: 'write_file',
    aliases: ['file_write'],
    label: 'File update',
    icon: FilePen,
    iconBgClass: 'bg-green-100',
    iconColorClass: 'text-green-600',
    detailKind: 'fileWrite',
    derive(_, parameters) {
      const path = coerceString(parameters?.path) || coerceString(parameters?.file_path) || coerceString(parameters?.filename)
      return { caption: path ? truncate(path, 40) : 'Update file' }
    },
  },
  {
    name: 'spawn_web_task',
    label: 'Browser task',
    icon: Globe,
    iconBgClass: 'bg-violet-100',
    iconColorClass: 'text-violet-600',
    detailKind: 'browserTask',
    derive(_, parameters) {
      let prompt = coerceString(parameters?.prompt)
      if (prompt?.toLowerCase().startsWith('task:')) {
        prompt = prompt.slice(5).trim()
      }
      return {
        caption: prompt ? truncate(prompt, 52) : null,
      }
    },
  },
  {
    name: 'spawn_agent',
    label: 'Create agent',
    icon: BotMessageSquare,
    iconBgClass: 'bg-emerald-100',
    iconColorClass: 'text-emerald-700',
    detailKind: 'spawnAgent',
    derive(entry, parameters) {
      const result = parseResultObject(entry.result)
      const statusRaw =
        (result ? coerceString(result['request_status']) : null) ??
        (result ? coerceString(result['status']) : null)
      const status = statusRaw ? statusRaw.toLowerCase() : null
      const requestedName = coerceString(result?.['requested_name']) || coerceString(parameters?.name)
      const message = result ? coerceString(result['message']) : null

      let caption: string | null = null
      if (status === 'pending') {
        caption = requestedName
          ? `Awaiting Create/Decline for ${requestedName}`
          : 'Awaiting Create/Decline approval'
      } else if (status === 'approved') {
        caption = requestedName ? `Created ${requestedName}` : 'Spawn request approved'
      } else if (status === 'rejected') {
        caption = 'Spawn request declined'
      } else if (message) {
        caption = truncate(message, 56)
      }

      return {
        label: requestedName ? `Create ${requestedName}` : 'Create agent',
        caption: caption ?? entry.caption ?? 'Create agent',
        summary: message ?? entry.summary ?? null,
        separateFromPreview: true,
      }
    },
  },
  {
    name: 'request_human_input',
    label: 'Human input request',
    icon: MessageSquareQuote,
    iconBgClass: 'bg-amber-100',
    iconColorClass: 'text-amber-700',
    detailKind: 'humanInputRequest',
    derive(entry, parameters) {
      const result = parseResultObject(entry.result)
      const question = coerceString(parameters?.['question']) || coerceString(result?.['question'])
      const batchRequests = Array.isArray(parameters?.['requests']) ? parameters?.['requests'] as unknown[] : []
      const resultRequests = Array.isArray(result?.['requests']) ? result?.['requests'] as unknown[] : []
      const resultRequestIds = Array.isArray(result?.['request_ids']) ? result?.['request_ids'] as unknown[] : []
      const requestQuestions = batchRequests
        .map((request) => (request && typeof request === 'object' ? coerceString((request as Record<string, unknown>)['question']) : null))
        .filter((value): value is string => Boolean(value))
      const questions = requestQuestions.length ? requestQuestions : (question ? [question] : [])
      const resultCount = coerceNumber(result?.['requests_count'])
      const derivedQuestionCount = resultCount ?? (resultRequests.length || resultRequestIds.length || questions.length || 1)
      const questionCount = Math.max(1, Math.trunc(derivedQuestionCount))
      const caption = questions[0] ? truncate(questions[0], 72) : null

      return {
        label: `Asked ${questionCount} Question${questionCount === 1 ? '' : 's'}`,
        caption: caption ?? entry.caption ?? 'Human input request',
        summary: null,
      }
    },
  },
  {
    name: 'request_contact_permission',
    label: 'Contact permission',
    icon: ContactRound,
    iconBgClass: 'bg-rose-100',
    iconColorClass: 'text-rose-600',
    detailKind: 'contactPermission',
    derive(entry, parameters) {
      const result = parseResultObject(entry.result)
      const contactsRaw = parameters?.contacts
      const contacts = Array.isArray(contactsRaw) ? contactsRaw : []
      const createdCountRaw = result?.['created_count']
      const alreadyAllowedRaw = result?.['already_allowed_count']
      const alreadyPendingRaw = result?.['already_pending_count']
      const message = result ? coerceString(result['message']) : null
      const status = result ? coerceString(result['status']) : null
      const createdCount = typeof createdCountRaw === 'number' ? createdCountRaw : null
      const alreadyAllowedCount = typeof alreadyAllowedRaw === 'number' ? alreadyAllowedRaw : null
      const alreadyPendingCount = typeof alreadyPendingRaw === 'number' ? alreadyPendingRaw : null

      let caption: string | null = null
      if (createdCount && createdCount > 0) {
        caption = `Awaiting approval for ${createdCount} contact${createdCount === 1 ? '' : 's'}`
      } else if (contacts.length) {
        caption = `Requested permission for ${contacts.length} contact${contacts.length === 1 ? '' : 's'}`
      } else if (message) {
        caption = truncate(message, 48)
      } else if (status) {
        caption = status
      }

      const summaryPieces: string[] = []
      if (message) {
        summaryPieces.push(message)
      }
      if (createdCount && createdCount > 0) {
        summaryPieces.push(`Created: ${createdCount}`)
      }
      if (alreadyAllowedCount && alreadyAllowedCount > 0) {
        summaryPieces.push(`Already allowed: ${alreadyAllowedCount}`)
      }
      if (alreadyPendingCount && alreadyPendingCount > 0) {
        summaryPieces.push(`Already pending: ${alreadyPendingCount}`)
      }

      return {
        caption: caption ?? entry.caption ?? 'Contact permission',
        summary: summaryPieces.length ? summaryPieces.join(' • ') : entry.summary ?? null,
      }
    },
  },
  {
    name: 'send_email',
    label: 'Email sent',
    icon: Mail,
    iconBgClass: 'bg-blue-100',
    iconColorClass: 'text-blue-600',
    detailKind: 'default',
    derive(entry, parameters) {
      const subject = coerceString(parameters?.['subject'])
      const toAddress = coerceString(parameters?.['to_address']) || coerceString(parameters?.['to'])
      const ccRaw = parameters?.['cc_addresses']
      const ccEntries = Array.isArray(ccRaw)
        ? (ccRaw as unknown[])
            .map((value) => coerceString(value))
            .filter((value): value is string => Boolean(value))
        : []

      const summaryParts: string[] = []
      if (toAddress) {
        summaryParts.push(`To ${toAddress}`)
      }
      if (ccEntries.length) {
        summaryParts.push(`CC ${ccEntries.join(', ')}`)
      }

      const caption = subject ? truncate(subject, 56) : toAddress ? `Email to ${truncate(toAddress, 42)}` : null
      const summaryText = summaryParts.length ? truncate(summaryParts.join(' • '), 96) : entry.summary ?? null

      return {
        caption: caption ?? entry.caption ?? 'Email sent',
        summary: summaryText,
      }
    },
  },
  {
    name: 'send_sms',
    label: 'SMS sent',
    icon: MessageSquareText,
    iconBgClass: 'bg-emerald-100',
    iconColorClass: 'text-emerald-600',
    detailKind: 'default',
    derive(entry, parameters) {
      const toNumber = coerceString(parameters?.['to_number'])
      const body = coerceString(parameters?.['body'])

      const caption = body ? truncate(body, 56) : toNumber ? `SMS to ${truncate(toNumber, 42)}` : null
      const summaryParts: string[] = []
      if (toNumber) {
        summaryParts.push(`To ${toNumber}`)
      }

      const ccRaw = parameters?.['cc_numbers']
      const ccList = Array.isArray(ccRaw)
        ? (ccRaw as unknown[])
            .map((value) => coerceString(value))
            .filter((value): value is string => Boolean(value))
        : []
      if (ccList.length) {
        summaryParts.push(`CC ${ccList.join(', ')}`)
      }

      return {
        caption: caption ?? entry.caption ?? 'SMS sent',
        summary: summaryParts.length ? truncate(summaryParts.join(' • '), 96) : entry.summary ?? null,
      }
    },
  },
  {
    name: 'send_web_message',
    label: 'Web message sent',
    icon: MessageCircle,
    iconBgClass: 'bg-violet-100',
    iconColorClass: 'text-violet-600',
    detailKind: 'default',
    derive(entry, parameters) {
      const body = coerceString(parameters?.['body']) || coerceString(parameters?.['message'])
      const recipient =
        coerceString(parameters?.['to_address']) ||
        coerceString(parameters?.['to']) ||
        coerceString(parameters?.['recipient'])

      const caption = body ? truncate(body, 56) : recipient ? `Web message to ${truncate(recipient, 42)}` : null
      const summary = recipient ? truncate(`To ${recipient}`, 96) : entry.summary ?? null

      return {
        caption: caption ?? entry.caption ?? 'Web message sent',
        summary,
      }
    },
  },
  {
    name: 'send_chat_message',
    label: 'Chat message sent',
    icon: MessageSquareDot,
    iconBgClass: 'bg-sky-100',
    iconColorClass: 'text-sky-600',
    detailKind: 'default',
    derive(entry, parameters) {
      const body = coerceString(parameters?.['body'])
      const toAddress = coerceString(parameters?.['to_address'])

      const caption = body ? truncate(body, 56) : toAddress ? `Chat to ${truncate(toAddress, 42)}` : null
      const summary = toAddress ? truncate(`To ${toAddress}`, 96) : entry.summary ?? null

      return {
        caption: caption ?? entry.caption ?? 'Chat message sent',
        summary,
      }
    },
  },
  {
    name: 'send_agent_message',
    label: 'Peer message sent',
    icon: BotMessageSquare,
    iconBgClass: 'bg-amber-100',
    iconColorClass: 'text-amber-600',
    detailKind: 'default',
    derive(entry, parameters) {
      const peerId = coerceString(parameters?.['peer_agent_id'])
      const message = coerceString(parameters?.['message'])

      const caption = message ? truncate(message, 56) : peerId ? `Message to ${truncate(peerId, 42)}` : null
      const summary = peerId ? truncate(`Peer agent ${peerId}`, 96) : entry.summary ?? null

      return {
        caption: caption ?? entry.caption ?? 'Peer message sent',
        summary,
      }
    },
  },
  {
    name: 'send_webhook_event',
    label: 'Webhook sent',
    icon: Webhook,
    iconBgClass: 'bg-orange-100',
    iconColorClass: 'text-orange-600',
    detailKind: 'default',
    derive(entry, parameters) {
      const resultData = parseResultObject(entry.result)
      const webhookName =
        coerceString(resultData?.['webhook_name']) || coerceString(parameters?.['webhook_id'])
      const statusValue = resultData?.['response_status']
      const status =
        typeof statusValue === 'number' || typeof statusValue === 'string' ? String(statusValue) : null

      const payload = parameters?.['payload']
      const payloadKeyCount =
        payload && typeof payload === 'object' && !Array.isArray(payload)
          ? Object.keys(payload as Record<string, unknown>).length
          : null

      const summaryParts: string[] = []
      if (webhookName) {
        summaryParts.push(webhookName)
      }
      if (status) {
        summaryParts.push(`Status ${status}`)
      }
      if (payloadKeyCount) {
        summaryParts.push(`${payloadKeyCount} field${payloadKeyCount === 1 ? '' : 's'}`)
      }

      const caption = webhookName ? `Webhook: ${truncate(webhookName, 40)}` : null

      return {
        caption: caption ?? entry.caption ?? 'Webhook triggered',
        summary: summaryParts.length ? truncate(summaryParts.join(' • '), 96) : entry.summary ?? null,
      }
    },
  },
  {
    name: 'secure_credentials_request',
    label: 'Credentials request',
    icon: KeyRound,
    iconBgClass: 'bg-amber-100',
    iconColorClass: 'text-amber-600',
    detailKind: 'secureCredentials',
    derive(entry, parameters) {
      const result = parseResultObject(entry.result)
      const credentialsRaw = parameters?.credentials
      const credentials = Array.isArray(credentialsRaw) ? credentialsRaw : []
      const createdCountRaw = result?.['created_count']
      const message = result ? coerceString(result['message']) : null
      const status = result ? coerceString(result['status']) : null
      const errorsRaw = result && Array.isArray(result['errors']) ? (result['errors'] as unknown[]) : null
      const createdCount = typeof createdCountRaw === 'number' ? createdCountRaw : null
      const firstCredential = credentials.length ? (credentials[0] as Record<string, unknown>) : null
      const firstName = firstCredential ? coerceString(firstCredential['name']) : null

      let caption: string | null = null
      if (createdCount && createdCount > 0) {
        caption = `Awaiting ${createdCount} credential${createdCount === 1 ? '' : 's'}`
      } else if (firstName) {
        caption = `Requesting ${firstName}`
      } else if (credentials.length) {
        caption = `Requesting ${credentials.length} credential${credentials.length === 1 ? '' : 's'}`
      } else if (status) {
        caption = status
      }

      const summaryPieces: string[] = []
      if (message) {
        summaryPieces.push(message)
      }
      if (errorsRaw && errorsRaw.length) {
        summaryPieces.push(`Errors: ${errorsRaw.length}`)
      }

      const summaryText = summaryPieces.length ? truncate(summaryPieces.join(' • '), 120) : entry.summary ?? null

      return {
        caption: caption ?? entry.caption ?? 'Credentials request',
        summary: summaryText,
      }
    },
  },
  {
    name: 'mcp_brightdata_search_engine',
    aliases: ['mcp_brightdata_search_engine_batch', 'search_engine', 'search_engine_batch'],
    label: 'Web search',
    icon: Search,
    iconBgClass: 'bg-blue-100',
    iconColorClass: 'text-blue-600',
    detailKind: 'brightDataSearch',
    derive(entry, parameters) {
      const query = extractBrightDataSearchQuery(parameters ?? null)
      const resultCount = extractBrightDataResultCount(entry.result)
      const captionParts: string[] = []

      if (query) {
        const cleanedQuery = query.replace(/\bsite:[^\s]+/gi, ' ').replace(/\s+/g, ' ').trim()
        captionParts.push(`“${truncate(cleanedQuery || query, 52)}”`)
      }
      if (resultCount !== null) {
        captionParts.push(`${resultCount} result${resultCount === 1 ? '' : 's'}`)
      }

      const caption = captionParts.length ? captionParts.join(' • ') : entry.caption ?? 'Web search'
      const summary =
        entry.summary ??
        (resultCount !== null ? `${resultCount} result${resultCount === 1 ? '' : 's'}` : null)

      return {
        caption,
        summary,
      }
    },
  },
  {
    name: 'mcp_brightdata_web_data_linkedin_person_profile',
    aliases: ['web_data_linkedin_person_profile'],
    label: 'LinkedIn Profile',
    icon: Linkedin,
    iconBgClass: LINKEDIN_ICON_BG_CLASS,
    iconColorClass: LINKEDIN_ICON_COLOR_CLASS,
    detailKind: 'linkedinPerson',
    derive(entry, parameters) {
      const caption = deriveLinkedInCaption(parameters, [
        'profile_url',
        'profile_id',
        'public_id',
        'person_url',
        'url',
        'username',
        'vanity',
        'name',
      ])
      return {
        caption: caption ?? entry.caption ?? 'LinkedIn Profile',
      }
    },
  },
  {
    name: 'mcp_brightdata_web_data_linkedin_company_profile',
    aliases: ['web_data_linkedin_company_profile'],
    label: 'LinkedIn Company',
    icon: Linkedin,
    iconBgClass: LINKEDIN_ICON_BG_CLASS,
    iconColorClass: LINKEDIN_ICON_COLOR_CLASS,
    detailKind: 'linkedinCompany',
    derive(entry, parameters) {
      const caption = deriveLinkedInCaption(parameters, [
        'company_name',
        'company',
        'organization',
        'company_url',
        'url',
        'profile_url',
        'name',
      ])
      return {
        caption: caption ?? entry.caption ?? 'LinkedIn Company',
      }
    },
  },
  {
    name: 'mcp_brightdata_web_data_linkedin_job_listings',
    aliases: ['web_data_linkedin_job_listings'],
    label: 'LinkedIn Jobs',
    icon: Linkedin,
    iconBgClass: LINKEDIN_ICON_BG_CLASS,
    iconColorClass: LINKEDIN_ICON_COLOR_CLASS,
    detailKind: 'linkedinJobListings',
    derive(entry, parameters) {
      const query = deriveLinkedInCaption(parameters, [
        'query',
        'keywords',
        'keyword',
        'company_name',
        'company',
        'title',
        'role',
        'location',
      ])

      const items = extractBrightDataArray(entry.result)
      const first = items[0]
      const title = coerceString(first?.['job_title']) || coerceString(first?.['title'])
      const company = coerceString(first?.['company_name']) || coerceString(first?.['company'])
      const fallback = [title, company].filter(Boolean).join(' • ') || coerceString(parameters?.['url'])
      const caption = query || fallback

      return {
        caption: caption ? truncate(caption, 56) : entry.caption ?? 'LinkedIn Jobs',
      }
    },
  },
  {
    name: 'mcp_brightdata_web_data_linkedin_posts',
    aliases: ['web_data_linkedin_posts'],
    label: 'LinkedIn Posts',
    icon: Linkedin,
    iconBgClass: LINKEDIN_ICON_BG_CLASS,
    iconColorClass: LINKEDIN_ICON_COLOR_CLASS,
    detailKind: 'linkedinPosts',
    derive(entry, parameters) {
      const items = extractBrightDataArray(entry.result)
      const first = items[0]
      const title = coerceString(first?.['title']) || coerceString(first?.['headline'])
      const author = coerceString(first?.['user_name']) || coerceString(first?.['user_id'])
      const url = coerceString(first?.['url']) || coerceString(first?.['post_url'])

      const caption = deriveLinkedInCaption(parameters, [
        'query',
        'keywords',
        'keyword',
        'profile_url',
        'company_name',
        'hashtag',
        'url',
      ]) || title || author || url
      return {
        caption: caption ?? entry.caption ?? 'LinkedIn Posts',
      }
    },
  },
  {
    name: 'mcp_brightdata_web_data_linkedin_people_search',
    aliases: ['web_data_linkedin_people_search'],
    label: 'LinkedIn Search',
    icon: Linkedin,
    iconBgClass: LINKEDIN_ICON_BG_CLASS,
    iconColorClass: LINKEDIN_ICON_COLOR_CLASS,
    detailKind: 'linkedinPeopleSearch',
    derive(entry, parameters) {
      const firstName = coerceString(parameters?.['first_name'])
      const lastName = coerceString(parameters?.['last_name'])
      const nameCaption = [firstName, lastName].filter(Boolean).join(' ')
      const caption = nameCaption || deriveLinkedInCaption(parameters, [
        'query',
        'keywords',
        'keyword',
        'company',
        'title',
        'role',
        'location',
      ])
      return {
        caption: caption ?? entry.caption ?? 'LinkedIn Search',
      }
    },
  },
  {
    name: 'mcp_brightdata_web_data_yahoo_finance_business',
    aliases: ['web_data_yahoo_finance_business'],
    label: 'Yahoo Finance',
    icon: BarChart3,
    iconBgClass: 'bg-amber-100',
    iconColorClass: 'text-amber-700',
    detailKind: 'yahooFinanceBusiness',
    derive(entry, parameters) {
      const ticker = coerceString(parameters?.['stock_ticker']) || coerceString(parameters?.['symbol'])
      const name = coerceString(parameters?.['name'])
      const captionPieces = [ticker ? ticker.toUpperCase() : null, name ? truncate(name, 44) : null].filter(Boolean)
      return {
        caption: captionPieces.length ? captionPieces.join(' • ') : entry.caption ?? 'Yahoo Finance',
      }
    },
  },
  {
    name: 'mcp_brightdata_web_data_reuter_news',
    aliases: ['web_data_reuter_news'],
    label: 'Reuters News',
    icon: Globe,
    iconBgClass: 'bg-blue-100',
    iconColorClass: 'text-blue-700',
    detailKind: 'reutersNews',
    derive(entry, parameters) {
      const articles = extractBrightDataArray(entry.result)
      const first = articles[0]
      const headline = coerceString(first?.['headline']) || coerceString(first?.['title'])
      const keyword = coerceString(first?.['keyword']) || coerceString(parameters?.['keyword'])
      const url = coerceString(first?.['url']) || coerceString(parameters?.['url'])
      const caption = headline || keyword || url
      return {
        caption: caption ? truncate(caption, 56) : entry.caption ?? 'Reuters News',
      }
    },
  },
  {
    name: 'mcp_brightdata_web_data_reddit_posts',
    aliases: ['web_data_reddit_posts'],
    label: 'Reddit Posts',
    icon: MessageSquareText,
    iconBgClass: 'bg-orange-100',
    iconColorClass: 'text-orange-700',
    detailKind: 'redditPosts',
    derive(entry, parameters) {
      const posts = extractBrightDataArray(entry.result)
      const first = posts[0]
      const title = coerceString(first?.['title'])
      const author = coerceString(first?.['author']) || coerceString(first?.['user_posted'])
      const community = coerceString(first?.['community_name']) || coerceString(first?.['subreddit'])
      const url = coerceString(first?.['url']) || coerceString(parameters?.['url'])
      const caption = title || community || author || url
      return {
        caption: caption ? truncate(caption, 56) : entry.caption ?? 'Reddit Posts',
      }
    },
  },
  {
    name: 'mcp_brightdata_web_data_zillow_properties_listing',
    aliases: ['web_data_zillow_properties_listing'],
    label: 'Zillow Listing',
    icon: Home,
    iconBgClass: 'bg-emerald-100',
    iconColorClass: 'text-emerald-700',
    detailKind: 'zillowListing',
    derive(entry, parameters) {
      const properties = extractBrightDataArray(entry.result)
      const first = properties[0]
      const addressRecord =
        first && typeof first === 'object' && 'address' in first && first.address && typeof first.address === 'object'
          ? (first.address as Record<string, unknown>)
          : null
      const street = coerceString(first?.['streetAddress']) || coerceString(addressRecord?.['streetAddress'])
      const city = coerceString(first?.['city']) || coerceString(addressRecord?.['city'])
      const state = coerceString(first?.['state']) || coerceString(addressRecord?.['state'])
      const location = [street, city, state].filter(Boolean).join(', ')
      const price = coerceNumber(first?.['price'])
      const priceCaption = price !== null ? `$${price.toLocaleString()}` : null
      const url = coerceString(parameters?.['url'])
      const baseCaption = location || url
      const combined = baseCaption && priceCaption ? `${baseCaption} • ${priceCaption}` : baseCaption ?? priceCaption
      return {
        caption: combined ? truncate(combined, 56) : entry.caption ?? 'Zillow Listing',
      }
    },
  },
  {
    name: 'mcp_brightdata_web_data_crunchbase_company',
    aliases: ['web_data_crunchbase_company'],
    label: 'Crunchbase Company',
    icon: Building2,
    iconBgClass: 'bg-emerald-100',
    iconColorClass: 'text-emerald-700',
    detailKind: 'crunchbaseCompany',
    derive(entry, parameters) {
      const caption = pickFirstParameter(parameters, ['company', 'company_id', 'name', 'organization', 'slug', 'url'])
      return {
        caption: caption ? truncate(caption, 56) : entry.caption ?? 'Crunchbase Company',
      }
    },
  },
  {
    name: 'mcp_brightdata_web_data_amazon_product',
    aliases: ['web_data_amazon_product'],
    label: 'Amazon Product',
    icon: ShoppingBag,
    iconBgClass: 'bg-orange-100',
    iconColorClass: 'text-orange-700',
    detailKind: 'amazonProduct',
    derive(entry, parameters) {
      const caption = pickFirstParameter(parameters, ['title', 'asin', 'url', 'product', 'name'])
      return {
        caption: caption ? truncate(caption, 56) : entry.caption ?? 'Amazon Product',
      }
    },
  },
  {
    name: 'mcp_brightdata_web_data_amazon_product_search',
    aliases: ['web_data_amazon_product_search'],
    label: 'Amazon Search',
    icon: ShoppingBag,
    iconBgClass: 'bg-orange-100',
    iconColorClass: 'text-orange-700',
    detailKind: 'amazonProductSearch',
    derive(entry, parameters) {
      const items = extractBrightDataArray(entry.result)
      const first = items[0]
      const queryFromItem = coerceString(first?.['keyword']) ||
        (first && typeof first === 'object' && 'input' in first && first.input && typeof first.input === 'object'
          ? coerceString((first.input as Record<string, unknown>)['keyword'])
          : null)
      const query = extractBrightDataSearchQuery(parameters) || coerceString(parameters?.['keyword']) || queryFromItem
      const name = coerceString(first?.['name']) || coerceString(first?.['title']) || coerceString(first?.['asin'])
      const count = extractBrightDataResultCount(entry.result) ?? (items.length ? items.length : null)
      const countLabel = count ? `${count} result${count === 1 ? '' : 's'}` : null
      const caption = query || name
      const combined = caption && countLabel ? `${caption} • ${countLabel}` : caption ?? countLabel
      return {
        caption: combined ? truncate(combined, 56) : entry.caption ?? 'Amazon Search',
      }
    },
  },
  {
    name: 'mcp_brightdata_web_data_amazon_product_reviews',
    aliases: ['web_data_amazon_product_reviews'],
    label: 'Amazon Reviews',
    icon: ShoppingBag,
    iconBgClass: 'bg-orange-100',
    iconColorClass: 'text-orange-700',
    detailKind: 'amazonProductReviews',
    derive(entry, parameters) {
      const urlCaption = pickFirstParameter(parameters, ['url', 'product_url'])
      const firstRecord = extractBrightDataArray(entry.result)[0]
      const productName = coerceString(firstRecord?.['product_name'])
      const ratingValue = coerceNumber(firstRecord?.['product_rating'])
      const ratingLabel =
        ratingValue !== null ? `${Number.isInteger(ratingValue) ? ratingValue : ratingValue.toFixed(1)}/5` : null
      const ratingCount = formatCount(coerceNumber(firstRecord?.['product_rating_count']))
      const ratingSummary = ratingLabel
        ? `${ratingLabel}${ratingCount ? ` (${ratingCount})` : ''}`
        : ratingCount
          ? `${ratingCount} ratings`
          : null
      const caption = productName || urlCaption
      const combined = caption && ratingSummary ? `${caption} • ${ratingSummary}` : caption ?? ratingSummary
      return {
        caption: combined ? truncate(combined, 56) : entry.caption ?? 'Amazon Reviews',
      }
    },
  },
  {
    name: 'mcp_brightdata_extract',
    aliases: ['extract'],
    label: 'Data Extract',
    icon: ScanText,
    iconBgClass: 'bg-fuchsia-100',
    iconColorClass: 'text-fuchsia-600',
    detailKind: 'brightDataSnapshot',
    derive(entry, parameters) {
      const url =
        coerceString(parameters?.['url']) ||
        coerceString(parameters?.['start_url']) ||
        null
      const caption = url ? truncate(url, 64) : null
      return {
        caption: caption ?? entry.caption ?? 'Data extract',
      }
    },
  },
  {
    name: 'mcp_brightdata_scrape_batch',
    aliases: ['scrape_batch'],
    label: 'Batch Scrape',
    icon: ScanText,
    iconBgClass: 'bg-fuchsia-100',
    iconColorClass: 'text-fuchsia-600',
    detailKind: 'brightDataSnapshot',
    derive(entry, parameters) {
      const urls = Array.isArray(parameters?.['urls']) ? parameters.urls as unknown[] : []
      const caption = urls.length ? `${urls.length} page${urls.length === 1 ? '' : 's'}` : null
      return {
        caption: caption ?? entry.caption ?? 'Batch scrape',
      }
    },
  },
  {
    name: 'mcp_brightdata_web_data_zoominfo_company_profile',
    aliases: ['web_data_zoominfo_company_profile'],
    label: 'ZoomInfo Company',
    icon: Database,
    iconBgClass: 'bg-emerald-100',
    iconColorClass: 'text-emerald-700',
    detailKind: 'default',
    derive(entry, parameters) {
      const caption = pickFirstParameter(parameters, ['company', 'name', 'url'])
      return {
        caption: caption ? truncate(caption, 56) : entry.caption ?? 'ZoomInfo Company',
      }
    },
  },
  {
    name: 'mcp_brightdata_scrape_as_markdown',
    aliases: ['scrape_as_markdown'],
    label: 'Browsing the web',
    icon: ScanText,
    iconBgClass: 'bg-fuchsia-100',
    iconColorClass: 'text-fuchsia-600',
    detailKind: 'brightDataSnapshot',
    derive(entry, parameters) {
      const url =
        coerceString(parameters?.['url']) ||
        coerceString(parameters?.['start_url']) ||
        coerceString(parameters?.['target_url']) ||
        null
      const caption = url ? truncate(url, 64) : null
      return {
        caption: caption ?? entry.caption ?? 'Browsing the web',
      }
    },
  },
  {
    name: 'mcp_brightdata_scrape_as_html',
    aliases: ['scrape_as_html'],
    label: 'Browsing the web',
    icon: ScanText,
    iconBgClass: 'bg-fuchsia-100',
    iconColorClass: 'text-fuchsia-600',
    detailKind: 'brightDataSnapshot',
    derive(entry, parameters) {
      const url =
        coerceString(parameters?.['url']) ||
        coerceString(parameters?.['start_url']) ||
        coerceString(parameters?.['target_url']) ||
        null
      const caption = url ? truncate(url, 64) : null
      return {
        caption: caption ?? entry.caption ?? 'Browsing the web',
      }
    },
  },
  {
    name: 'think',
    aliases: ['reasoning'],
    label: 'Analysis',
    icon: BrainCog,
    iconBgClass: 'bg-yellow-100',
    iconColorClass: 'text-yellow-600',
    detailKind: 'analysis',
    derive(entry) {
      const summary = coerceString(entry.summary) || coerceString(entry.caption) || coerceString(entry.result)
      return {
        caption: summary ? truncate(summary, 64) : 'Analysis',
        summary,
      }
    },
  },
]

export const DEFAULT_TOOL_METADATA: ToolMetadataConfig = {
  name: 'default',
  label: 'Agent action',
  icon: Workflow,
  iconBgClass: 'bg-slate-100',
  iconColorClass: 'text-slate-600',
  detailKind: 'default',
}

const TOOL_METADATA_MAP: Map<string, ToolMetadataConfig> = (() => {
  const map = new Map<string, ToolMetadataConfig>()
  const register = (config: ToolMetadataConfig) => {
    map.set(config.name, config)
    config.aliases?.forEach((alias) => map.set(alias, config))
  }
  TOOL_METADATA_CONFIGS.forEach(register)
  register(DEFAULT_TOOL_METADATA)
  return map
})()

export function getSharedToolMetadata(toolName: string | null | undefined): ToolMetadataConfig {
  const normalized = (toolName ?? '').toLowerCase()
  return TOOL_METADATA_MAP.get(normalized) ?? DEFAULT_TOOL_METADATA
}

const KNOWN_SERVER_PREFIXES = ['brightdata_', 'bright_data_']
const KNOWN_CATEGORY_PREFIXES = ['web_data_', 'scraping_browser_']

const BRAND_CASING: Record<string, string> = {
  linkedin: 'LinkedIn',
  zoominfo: 'ZoomInfo',
  crunchbase: 'Crunchbase',
  youtube: 'YouTube',
  tiktok: 'TikTok',
  facebook: 'Facebook',
  instagram: 'Instagram',
  github: 'GitHub',
  reddit: 'Reddit',
  amazon: 'Amazon',
  walmart: 'Walmart',
  zillow: 'Zillow',
  ebay: 'eBay',
  bestbuy: 'Best Buy',
  homedepot: 'Home Depot',
  api: 'API',
  csv: 'CSV',
  pdf: 'PDF',
  html: 'HTML',
  url: 'URL',
  sql: 'SQL',
}

function titleCase(slug: string): string {
  return slug
    .split(/[_-]+/)
    .filter(Boolean)
    .map((word) => BRAND_CASING[word.toLowerCase()] ?? word.charAt(0).toUpperCase() + word.slice(1))
    .join(' ')
}

export function toFriendlyToolName(rawName: string): string {
  const config = TOOL_METADATA_MAP.get(rawName.toLowerCase())
  if (config && config !== DEFAULT_TOOL_METADATA) {
    return config.label
  }

  let slug = rawName
  if (slug.startsWith('custom_')) {
    slug = slug.slice('custom_'.length)
  }
  if (slug.startsWith('mcp_')) {
    slug = slug.slice(4)
  }
  for (const prefix of KNOWN_SERVER_PREFIXES) {
    if (slug.startsWith(prefix)) {
      slug = slug.slice(prefix.length)
      break
    }
  }
  for (const prefix of KNOWN_CATEGORY_PREFIXES) {
    if (slug.startsWith(prefix)) {
      slug = slug.slice(prefix.length)
      break
    }
  }
  return titleCase(slug)
}

export type FriendlyToolInfo = {
  label: string
  icon: LucideIcon
  iconBgClass: string
  iconColorClass: string
}

export function getFriendlyToolInfo(rawName: string): FriendlyToolInfo {
  if (rawName.toLowerCase().startsWith('custom_')) {
    return {
      label: toFriendlyToolName(rawName),
      icon: BotMessageSquare,
      iconBgClass: 'bg-cyan-100',
      iconColorClass: 'text-cyan-700',
    }
  }
  const config = TOOL_METADATA_MAP.get(rawName.toLowerCase())
  if (config && config !== DEFAULT_TOOL_METADATA) {
    return {
      label: config.label,
      icon: config.icon,
      iconBgClass: config.iconBgClass,
      iconColorClass: config.iconColorClass,
    }
  }
  return {
    label: toFriendlyToolName(rawName),
    icon: Workflow,
    iconBgClass: 'bg-slate-100',
    iconColorClass: 'text-slate-600',
  }
}

export function buildToolDescriptorMap(
  resolveDetailComponent: (detailKind: DetailKind) => ToolDescriptor['detailComponent'],
): Map<string, ToolDescriptor> {
  const map: Map<string, ToolDescriptor> = new Map()
  const register = (config: ToolMetadataConfig) => {
    const descriptor: ToolDescriptor = {
      name: config.name,
      aliases: config.aliases,
      label: config.label,
      icon: config.icon,
      iconBgClass: config.iconBgClass,
      iconColorClass: config.iconColorClass,
      skip: config.skip,
      derive: config.derive,
      detailComponent: resolveDetailComponent(config.detailKind),
    }
    map.set(config.name, descriptor)
    config.aliases?.forEach((alias) => map.set(alias, descriptor))
  }
  TOOL_METADATA_CONFIGS.forEach(register)
  register(DEFAULT_TOOL_METADATA)
  return map
}
