import type { DriveFileInfo } from "@/lib/api/types"
import { parentFolderPath } from "@/lib/drive/drive-search"
import { normalizeDriveFolderPath } from "@/lib/drive/drive-sidebar-tree"
import type { DriveFiltersSnapshot } from "@/lib/stores/drive-filters-store"
import { driveFiltersActive } from "@/lib/stores/drive-filters-store"

export type DriveMimeCategory =
  | "folder"
  | "document"
  | "spreadsheet"
  | "presentation"
  | "image"
  | "pdf"
  | "video"
  | "audio"
  | "archive"
  | "other"

export type DriveSourceId = "ultimail" | "ultimeet"

const ARCHIVE_EXT = new Set(["zip", "rar", "7z", "tar", "gz", "bz2"])
const AUDIO_EXT = new Set(["mp3", "wav", "ogg", "flac", "m4a", "aac"])
const IMAGE_EXT = new Set(["jpg", "jpeg", "png", "gif", "webp", "svg", "bmp", "avif", "heic"])
const VIDEO_EXT = new Set(["mp4", "webm", "mov", "mkv", "ogv", "m4v"])

function ext(name: string) {
  const i = name.lastIndexOf(".")
  return i > 0 ? name.slice(i + 1).toLowerCase() : ""
}

export function classifyDriveFile(file: DriveFileInfo): DriveMimeCategory {
  if (file.type === "directory") return "folder"
  const mime = (file.mime_type ?? "").toLowerCase()
  const e = ext(file.name)
  if (mime.includes("pdf") || e === "pdf") return "pdf"
  if (mime.startsWith("image/") || IMAGE_EXT.has(e)) return "image"
  if (mime.startsWith("video/") || VIDEO_EXT.has(e)) return "video"
  if (mime.startsWith("audio/") || AUDIO_EXT.has(e)) return "audio"
  if (
    mime.includes("zip") ||
    mime.includes("archive") ||
    ARCHIVE_EXT.has(e)
  ) {
    return "archive"
  }
  if (
    mime.includes("spreadsheet") ||
    mime.includes("excel") ||
    ["xls", "xlsx", "ods", "csv"].includes(e)
  ) {
    return "spreadsheet"
  }
  if (
    mime.includes("presentation") ||
    mime.includes("powerpoint") ||
    ["ppt", "pptx", "odp"].includes(e)
  ) {
    return "presentation"
  }
  if (
    mime.includes("word") ||
    mime.includes("document") ||
    mime.includes("opendocument.text") ||
    ["doc", "docx", "odt", "rtf", "txt"].includes(e)
  ) {
    return "document"
  }
  return "other"
}

export function matchesDriveSource(file: DriveFileInfo, source: DriveSourceId): boolean {
  if (file.source === source) return true

  const p = file.path.toLowerCase()
  const n = file.name.toLowerCase()
  if (source === "ultimail") {
    return (
      p.includes("/ultimail") ||
      p.includes("/mail/") ||
      n.includes("ultimail") ||
      (file.mime_type ?? "").includes("rfc822")
    )
  }
  return (
    file.source === "ultimeet" ||
    p.includes("/ultimeet") ||
    p.includes("/meet") ||
    p.includes("/recordings") ||
    n.includes("ultimeet") ||
    n.includes("meet-")
  )
}

function parseModified(iso: string): Date | null {
  const d = new Date(iso)
  return Number.isNaN(d.getTime()) ? null : d
}

function inDateRange(file: DriveFileInfo, filters: DriveFiltersSnapshot): boolean {
  const { datePreset, dateFrom, dateTo } = filters
  if (!datePreset) return true
  const modified = parseModified(file.last_modified)
  if (!modified) return true

  const now = new Date()
  const startOfDay = (d: Date) => new Date(d.getFullYear(), d.getMonth(), d.getDate())

  if (datePreset === "today") {
    const today = startOfDay(now)
    return modified >= today
  }
  if (datePreset === "last7") {
    const from = new Date(now)
    from.setDate(from.getDate() - 7)
    return modified >= from
  }
  if (datePreset === "last30") {
    const from = new Date(now)
    from.setDate(from.getDate() - 30)
    return modified >= from
  }
  if (datePreset === "thisYear") {
    return modified.getFullYear() === now.getFullYear()
  }
  if (datePreset === "lastYear") {
    return modified.getFullYear() === now.getFullYear() - 1
  }
  if (datePreset === "custom" && dateFrom) {
    const from = startOfDay(new Date(dateFrom))
    const to = dateTo ? new Date(dateTo) : now
    return modified >= from && modified <= to
  }
  return true
}

export function matchesDriveFilters(
  file: DriveFileInfo,
  filters: DriveFiltersSnapshot
): boolean {
  if (filters.types.size > 0) {
    const cat = classifyDriveFile(file)
    if (!filters.types.has(cat)) return false
  }
  if (filters.sources.size > 0) {
    const ok = [...filters.sources].some((s) => matchesDriveSource(file, s))
    if (!ok) return false
  }
  if (!matchesContact(file, filters)) return false
  if (!inDateRange(file, filters)) return false
  return true
}

function isPathUnderScope(path: string, scopePath: string): boolean {
  const normalized = normalizeDriveFolderPath(path)
  const scope = normalizeDriveFolderPath(scopePath)
  if (scope === "/") return true
  return normalized === scope || normalized.startsWith(`${scope}/`)
}

/** Folder paths that contain (or nest) at least one file matching filters. */
export function buildDriveFolderPathsWithMatches(
  corpus: DriveFileInfo[],
  filters: DriveFiltersSnapshot,
  scopePath = "/"
): Set<string> {
  const keep = new Set<string>()
  const scope = normalizeDriveFolderPath(scopePath)

  for (const file of corpus) {
    if (file.type === "directory") continue
    if (!matchesDriveFilters(file, filters)) continue

    let dir = parentFolderPath(file.path)
    while (dir !== "/" && isPathUnderScope(dir, scope)) {
      const normalized = normalizeDriveFolderPath(dir)
      keep.add(normalized)
      if (normalized === scope) break
      dir = parentFolderPath(normalized)
    }
  }

  return keep
}

function matchesContact(file: DriveFileInfo, filters: DriveFiltersSnapshot): boolean {
  if (!filters.contactEmail && !filters.contactName) return true
  const hay = `${file.path} ${file.name}`.toLowerCase()
  if (filters.contactEmail && hay.includes(filters.contactEmail.toLowerCase())) {
    return true
  }
  if (filters.contactName) {
    const parts = filters.contactName.toLowerCase().split(/\s+/).filter(Boolean)
    if (parts.length > 0 && parts.every((p) => hay.includes(p))) return true
  }
  return false
}

export function applyDriveFilters(
  items: DriveFileInfo[],
  filters: DriveFiltersSnapshot,
  options?: {
    /** When set, only folders in this set stay visible (plus direct filter matches). */
    folderKeepPaths?: Set<string>
    /** Corpus for folder pruning when folderKeepPaths is omitted. */
    matchCorpus?: DriveFileInfo[]
    /** Limit folder pruning to descendants of this path (default `/`). */
    scopePath?: string
  }
): DriveFileInfo[] {
  if (!driveFiltersActive(filters)) return items

  const folderKeepPaths =
    options?.folderKeepPaths ??
    (options?.matchCorpus
      ? buildDriveFolderPathsWithMatches(
          options.matchCorpus,
          filters,
          options.scopePath ?? "/"
        )
      : undefined)

  return items.filter((file) => {
    if (file.type === "directory") {
      const path = normalizeDriveFolderPath(file.path)
      if (folderKeepPaths?.has(path)) return true
      return matchesDriveFilters(file, filters)
    }
    return matchesDriveFilters(file, filters)
  })
}

export { driveFiltersActive as hasActiveDriveFilters }
