import type { Email } from "@/lib/email-data"
import {
  folderTree as defaultFolderTree,
  sidebarNavFolderIdToLabel as defaultSidebarNavFolderIdToLabel,
  defaultNavLabelRowsSnapshot,
  type LabelRowItem,
} from "@/lib/sidebar-nav-data"
import { collectSubtreeFolderIds } from "@/lib/sidebar-nav-maps"
import type { FolderTreeNode } from "@/lib/sidebar-nav-maps"

export type MailFolderFilterCtx = {
  starredEmailIds: string[]
  importantEmailIds: string[]
}

/** Carte navigation dynamique (sidebar). Si absent, valeurs par défaut du module. */
export type MailNavFolderMaps = {
  folderIdToLabel: Record<string, string>
  folderTree: FolderTreeNode[]
  labelRows: LabelRowItem[]
}

function hasFutureScheduledSend(email: Email): boolean {
  if (!email.scheduledSendAt) return false
  const t = new Date(email.scheduledSendAt).getTime()
  if (!Number.isFinite(t)) return false
  return t > Date.now()
}

function effectiveStarred(email: Email, ctx: MailFolderFilterCtx): boolean {
  return ctx.starredEmailIds.includes(email.id) || email.starred
}

function effectiveImportant(email: Email, ctx: MailFolderFilterCtx): boolean {
  return ctx.importantEmailIds.includes(email.id) || email.important
}

function isInInbox(email: Email): boolean {
  if (email.deleted) return false
  if (email.spam) return false
  if (hasFutureScheduledSend(email)) return false
  const ls = email.labels
  if (!ls?.length) return true
  return ls.includes("inbox")
}

function labelRowForNavId(
  folderId: string,
  rows: readonly LabelRowItem[]
): LabelRowItem | undefined {
  return rows.find((r) => r.id === folderId)
}

function resolveNavMaps(maps?: MailNavFolderMaps | null): MailNavFolderMaps {
  if (maps) return maps
  return {
    folderIdToLabel: defaultSidebarNavFolderIdToLabel as Record<string, string>,
    folderTree: defaultFolderTree,
    labelRows: defaultNavLabelRowsSnapshot,
  }
}

function emailHasAnyLabel(email: Email, labels: string[]): boolean {
  const ls = email.labels
  if (!ls?.length) return false
  const lower = new Set(ls.map((x) => x.toLowerCase()))
  return labels.some((lab) => lower.has(lab.toLowerCase()))
}

function matchesFolderLabelRow(
  email: Email,
  folderId: string,
  maps: MailNavFolderMaps
): boolean {
  const row = labelRowForNavId(folderId, maps.labelRows)
  if (row && row.enabled === false) return false
  const label = maps.folderIdToLabel[folderId]
  if (!label) return false
  return emailHasAnyLabel(email, [label])
}

/** Dossier hiérarchique : ce nœud ou n'importe quel sous-dossier (décompte unique par mail). */
function matchesLabelNav(
  email: Email,
  folderId: string,
  maps: MailNavFolderMaps,
  subtreeIdsCache?: Map<string, string[] | null>
): boolean {
  let subtreeIds: string[] | null
  if (subtreeIdsCache) {
    if (!subtreeIdsCache.has(folderId)) {
      subtreeIdsCache.set(
        folderId,
        collectSubtreeFolderIds(maps.folderTree, folderId)
      )
    }
    subtreeIds = subtreeIdsCache.get(folderId) ?? null
  } else {
    subtreeIds = collectSubtreeFolderIds(maps.folderTree, folderId)
  }
  if (subtreeIds) {
    return subtreeIds.some((id) => matchesFolderLabelRow(email, id, maps))
  }
  return matchesFolderLabelRow(email, folderId, maps)
}

/** Onglet Principale : boîte sans libellés système « exclude » actifs. */
export function emailMatchesInboxPrimaryTab(
  email: Email,
  ctx: MailFolderFilterCtx,
  maps: MailNavFolderMaps,
  subtreeIdsCache?: Map<string, string[] | null>
): boolean {
  if (!emailMatchesFolder(email, "inbox", ctx, maps, subtreeIdsCache)) return false
  if (email.deleted) return false
  if (hasFutureScheduledSend(email)) return false
  for (const row of maps.labelRows) {
    if (row.enabled === false) continue
    if (!row.excludeFromPrincipal) continue
    if (emailHasAnyLabel(email, [row.label])) return false
  }
  return true
}

export function emailMatchesFolder(
  email: Email,
  folderId: string,
  ctx: MailFolderFilterCtx,
  maps?: MailNavFolderMaps | null,
  /** Réutiliser entre appels (ex. `computeFolderUnreadCounts`) pour éviter de rescanner l’arbre à chaque mail. */
  subtreeIdsCache?: Map<string, string[] | null>
): boolean {
  const nav = resolveNavMaps(maps)

  if (email.deleted && folderId !== "trash") {
    return false
  }

  switch (folderId) {
    case "inbox":
      return isInInbox(email)
    case "starred":
      return effectiveStarred(email, ctx)
    case "snoozed":
      return (email.labels?.includes("snoozed") ?? false) && !email.deleted
    case "important":
      return effectiveImportant(email, ctx)
    case "sent":
      return (email.labels?.includes("sent") ?? false) && !email.deleted
    case "drafts":
      return (email.labels?.includes("drafts") ?? false) && !email.deleted
    case "scheduled":
      return !email.deleted && hasFutureScheduledSend(email)
    case "spam":
      return (
        !email.deleted &&
        (email.spam === true || (email.labels?.includes("spam") ?? false))
      )
    case "trash":
      return email.deleted === true
    default:
      break
  }

  const row = labelRowForNavId(folderId, nav.labelRows)
  if (row && row.enabled === false) return false

  if (nav.folderIdToLabel[folderId]) {
    return matchesLabelNav(email, folderId, nav, subtreeIdsCache)
  }

  if (email.labels?.includes(folderId)) return true

  return false
}
