import type { Email } from "@/lib/email-data"
import { applyLabelEditsToEmails, mergeEmailNotSpam } from "@/lib/label-edits"
import {
  emailMatchesFolder,
  type MailFolderFilterCtx,
  type MailNavFolderMaps,
} from "@/lib/mail-folder-filter"
import type { LabelEditState } from "@/lib/stores/mail-store"
import {
  folderTree as defaultFolderTree,
  sidebarNavFolderIdToLabel,
  defaultNavLabelRowsSnapshot,
  type FolderTreeNode,
} from "@/lib/sidebar-nav-data"

export const MAIN_NAV_FOLDER_IDS = [
  "inbox",
  "starred",
  "snoozed",
  "important",
  "sent",
  "drafts",
  "scheduled",
  "spam",
  "trash",
] as const

function collectTreeIds(nodes: FolderTreeNode[]): string[] {
  const out: string[] = []
  for (const n of nodes) {
    out.push(n.id)
    if (n.children?.length) out.push(...collectTreeIds(n.children))
  }
  return out
}

const MAIN_SET = new Set<string>(MAIN_NAV_FOLDER_IDS)

/** Tous les ids de lignes sidebar pour lesquelles on calcule un décompte « non lus ». */
export function allSidebarNavFolderIds(maps?: MailNavFolderMaps | null): string[] {
  const tree = maps?.folderTree ?? defaultFolderTree
  const rows = maps?.labelRows ?? defaultNavLabelRowsSnapshot
  const idToLabel =
    maps?.folderIdToLabel ?? (sidebarNavFolderIdToLabel as Record<string, string>)
  const treeIds = collectTreeIds(tree)
  const labelRowIds = Object.keys(idToLabel).filter((id) => {
    if (MAIN_SET.has(id)) return false
    if (id === "scheduled") return false
    if (treeIds.includes(id)) return false
    const row = rows.find((r) => r.id === id)
    if (row && row.enabled === false) return false
    return true
  })
  return [...MAIN_NAV_FOLDER_IDS, ...treeIds, ...labelRowIds]
}

function effectiveRead(
  email: Email,
  readOverrides: Record<string, boolean>
): boolean {
  return readOverrides[email.id] !== undefined
    ? readOverrides[email.id]!
    : email.read
}

export function countUnreadInFolder(
  allEmails: Email[],
  folderId: string,
  ctx: MailFolderFilterCtx,
  hiddenIds: Set<string>,
  readOverrides: Record<string, boolean>,
  maps?: MailNavFolderMaps | null,
  subtreeIdsCache?: Map<string, string[] | null>
): number {
  if (folderId === "scheduled" || folderId === "snoozed") {
    let n = 0
    for (const e of allEmails) {
      if (hiddenIds.has(e.id)) continue
      if (!emailMatchesFolder(e, folderId, ctx, maps, subtreeIdsCache)) continue
      n++
    }
    return n
  }

  let n = 0
  for (const e of allEmails) {
    if (hiddenIds.has(e.id)) continue
    if (!emailMatchesFolder(e, folderId, ctx, maps, subtreeIdsCache)) continue
    if (!effectiveRead(e, readOverrides)) n++
  }
  return n
}

export function computeFolderUnreadCounts(
  allEmails: Email[],
  ctx: MailFolderFilterCtx,
  hiddenEmailIds: string[],
  readOverrides: Record<string, boolean>,
  maps?: MailNavFolderMaps | null,
  labelEdits?: LabelEditState,
  notSpamEmailIds?: readonly string[]
): Record<string, number> {
  let pool: Email[] =
    labelEdits &&
    (Object.keys(labelEdits.additions).length > 0 ||
      Object.keys(labelEdits.removals).length > 0)
      ? applyLabelEditsToEmails(allEmails, labelEdits)
      : allEmails
  if (notSpamEmailIds && notSpamEmailIds.length > 0) {
    pool = pool.map((e) => mergeEmailNotSpam(e, notSpamEmailIds))
  }
  const hidden = new Set(hiddenEmailIds)
  const subtreeIdsCache = new Map<string, string[] | null>()
  const out: Record<string, number> = {}
  for (const id of allSidebarNavFolderIds(maps)) {
    out[id] = countUnreadInFolder(
      pool,
      id,
      ctx,
      hidden,
      readOverrides,
      maps,
      subtreeIdsCache
    )
  }
  return out
}
