export interface ScaleDictLeaf {
  id: string
  code: string
  name: string
  hasCost: boolean
  hasArea: boolean
}

export interface ScaleDictGroup {
  id: string
  code: string
  name: string
  children: ScaleDictLeaf[]
}

type MajorLite = {
  code: string
  name: string
  hasCost?: boolean
  hasArea?: boolean
}

export const buildScaleDetailDict = (
  entries: Array<[string, MajorLite]>,
  includeLeaf: (params: { id: string; item: MajorLite; hasCost: boolean; hasArea: boolean }) => boolean
): ScaleDictGroup[] => {
  const groupMap = new Map<string, ScaleDictGroup>()
  const groupOrder: string[] = []
  const codeLookup = new Map(entries.map(([key, item]) => [item.code, { id: key, code: item.code, name: item.name }]))

  for (const [key, item] of entries) {
    const code = item.code
    const isGroup = !code.includes('-')
    if (isGroup) {
      if (!groupMap.has(code)) groupOrder.push(code)
      groupMap.set(code, {
        id: key,
        code,
        name: item.name,
        children: []
      })
      continue
    }

    const parentCode = code.split('-')[0]
    if (!groupMap.has(parentCode)) {
      const parent = codeLookup.get(parentCode)
      if (!groupOrder.includes(parentCode)) groupOrder.push(parentCode)
      groupMap.set(parentCode, {
        id: parent?.id || `group-${parentCode}`,
        code: parentCode,
        name: parent?.name || parentCode,
        children: []
      })
    }

    const hasCost = item.hasCost !== false
    const hasArea = item.hasArea !== false
    if (!includeLeaf({ id: key, item, hasCost, hasArea })) continue

    groupMap.get(parentCode)!.children.push({
      id: key,
      code,
      name: item.name,
      hasCost,
      hasArea
    })
  }

  return groupOrder.map(code => groupMap.get(code)).filter((group): group is ScaleDictGroup => Boolean(group))
}

export const buildScaleIdLabelMap = (detailDict: ScaleDictGroup[]) => {
  const idLabelMap = new Map<string, string>()
  for (const group of detailDict) {
    idLabelMap.set(group.id, `${group.code} ${group.name}`)
    for (const child of group.children) {
      idLabelMap.set(child.id, `${child.code} ${child.name}`)
    }
  }
  return idLabelMap
}

export const buildScaleRowsFromDict = <TRow>(options: {
  detailDict: ScaleDictGroup[]
  projectCount: number
  activeIndustryCode: string
  isMajorInIndustryScope: (groupId: string, industryCode: string) => boolean
  buildScopedRowId: (projectIndex: number, majorId: string) => string
  buildProjectGroupPathKey: (projectIndex: number) => string
  isMutipleService: boolean
  createRow: (params: {
    projectIndex: number
    group: ScaleDictGroup
    child: ScaleDictLeaf
    rowId: string
    path: string[]
  }) => TRow
}) => {
  if (!options.activeIndustryCode) return [] as TRow[]
  const rows: TRow[] = []
  for (let projectIndex = 1; projectIndex <= options.projectCount; projectIndex++) {
    for (const group of options.detailDict) {
      if (options.activeIndustryCode && !options.isMajorInIndustryScope(group.id, options.activeIndustryCode)) continue
      for (const child of group.children) {
        const rowId = options.buildScopedRowId(projectIndex, child.id)
        rows.push(options.createRow({
          projectIndex,
          group,
          child,
          rowId,
          path: options.isMutipleService
            ? [options.buildProjectGroupPathKey(projectIndex), group.id, rowId]
            : [group.id, rowId]
        }))
      }
    }
  }
  return rows
}
