import type { ExpertDefinition } from "@qjclaw/shared-types"
import { getProjectDisplayName } from "../experts/expertDisplay"
import type { ExpertProject, SidebarExpertEntry } from "./ExpertTree"

const SIDEBAR_EXPERT_ENTRY_ORDER = new Map<string, number>([
  ["xhs", 20],
  ["douyin", 21],
  ["sales-champion", 22],
  ["content-account-planning", 23],
  ["zhihu", 24],
  ["wechat-official-account", 30],
  ["x-platform", 31],
  ["tiktok", 32],
  ["poster", 33],
  ["geo", 34],
  ["precision-leads", 35]
])

function normalizeText(value: string | undefined): string {
  return value?.trim().toLowerCase() ?? ""
}

export function matchesExpertProject(project: ExpertProject, definition: ExpertDefinition): boolean {
  const seed = [project.id, project.name, project.displayName, project.platform]
    .filter(Boolean)
    .join(" ")
    .toLowerCase()

  return definition.projectMatchKeywords.some((keyword) => {
    const normalizedKeyword = normalizeText(keyword)
    return normalizedKeyword ? seed.includes(normalizedKeyword) : false
  })
}

export function resolveExpertProject(projects: ExpertProject[], definition: ExpertDefinition): ExpertProject | undefined {
  return projects.find((project) => matchesExpertProject(project, definition))
}

export function resolveExpertDisplayName(definition: ExpertDefinition, project?: ExpertProject, defaultChatName?: string): string {
  return definition.name || getProjectDisplayName(project, defaultChatName)
}

export function buildProjectExpertDefinition(project: ExpertProject, definition?: ExpertDefinition, defaultChatName?: string): ExpertDefinition {
  if (definition) {
    return definition
  }

  const projectMatchKeywords = Array.from(new Set(
    [project.id, project.name, project.displayName, project.platform]
      .map((value) => value?.trim())
      .filter((value): value is string => Boolean(value))
  ))

  return {
    id: project.id,
    name: getProjectDisplayName(project, defaultChatName),
    entryMode: "standalone",
    description: project.description,
    promptAvailable: true,
    projectMatchKeywords
  }
}

export function buildShortcutPrompt(definition: ExpertDefinition): string {
  return definition.starterPrompt?.trim() ?? ""
}

export function getSidebarExpertEntryOrder(entry: SidebarExpertEntry): number {
  return SIDEBAR_EXPERT_ENTRY_ORDER.get(entry.definition.id)
    ?? SIDEBAR_EXPERT_ENTRY_ORDER.get(entry.project?.id ?? "")
    ?? 999
}

export function buildStandaloneExpertEntries(
  definitions: ExpertDefinition[],
  visibleProjects: ExpertProject[],
  defaultChatName?: string
): SidebarExpertEntry[] {
  return definitions.map((definition) => {
    const project = resolveExpertProject(visibleProjects, definition)
    return {
      definition,
      project,
      displayName: resolveExpertDisplayName(definition, project, defaultChatName),
      isAvailable: definition.promptAvailable
    }
  })
}

export function buildProjectExpertEntries(
  visibleProjects: ExpertProject[],
  standaloneExpertDefinitions: ExpertDefinition[],
  defaultChatName?: string
): SidebarExpertEntry[] {
  return visibleProjects
    .filter((project) => !standaloneExpertDefinitions.some((definition) => matchesExpertProject(project, definition)))
    .map((project) => {
      const definition = buildProjectExpertDefinition(project, undefined, defaultChatName)
      return {
        definition,
        project,
        displayName: resolveExpertDisplayName(definition, project, defaultChatName),
        isAvailable: project.ready !== false
      }
    })
}

export function buildHomeShortcutEntries(definitions: ExpertDefinition[]): SidebarExpertEntry[] {
  return definitions.map((definition) => ({
    definition,
    project: undefined,
    displayName: definition.name,
    isAvailable: definition.promptAvailable
  }))
}

export function buildSidebarExpertEntries(
  standaloneExpertEntries: SidebarExpertEntry[],
  projectExpertEntries: SidebarExpertEntry[],
  homeShortcutEntries: SidebarExpertEntry[]
): SidebarExpertEntry[] {
  return [...standaloneExpertEntries, ...projectExpertEntries, ...homeShortcutEntries]
    .sort((left, right) => getSidebarExpertEntryOrder(left) - getSidebarExpertEntryOrder(right))
}
