"use client"

import {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
  type DragEvent,
  type MouseEvent,
} from "react"
import { useEmailDrag } from "@/lib/drag-context"
import type { EmailListData } from "@/components/gmail/email-list/hooks/use-email-list-data"
import type { EmailListLabels } from "@/components/gmail/email-list/hooks/use-email-list-labels"

export function useEmailListSelection(
  data: EmailListData,
  labels: EmailListLabels
) {
  const {
    selectedFolder,
    isViewMode,
    isXs,
    touchNav,
    pageIds,
    listEmails,
    effectiveRead,
    effectiveStarred,
    readOverrides,
    allEmails,
    setReadOverrides,
    mailActions,
  } = data

  const { moveEmailsToTarget } = labels

  const { beginDrag, registerOnDrop } = useEmailDrag()

  const [selectedEmails, setSelectedEmails] = useState<string[]>([])
  const rowContextMenuOpenedAtRef = useRef(0)
  const contextMenuTargetIdsRef = useRef<string[]>([])
  const lastSelectionAnchorIdRef = useRef<string | null>(null)
  const [bulkSelectMenuOpen, setBulkSelectMenuOpen] = useState(false)
  const [mobileSelectionMode, setMobileSelectionMode] = useState(false)
  const [mobileXsMoreMenuOpen, setMobileXsMoreMenuOpen] = useState(false)
  const [mobileXsMoveSheetOpen, setMobileXsMoveSheetOpen] = useState(false)
  const [mobileXsLabelSheetOpen, setMobileXsLabelSheetOpen] = useState(false)
  const [swipeLabelEmailId, setSwipeLabelEmailId] = useState<string | null>(null)
  const [openSwipeRowId, setOpenSwipeRowId] = useState<string | null>(null)

  const touchListSwipeEnabled = touchNav && !mobileSelectionMode && !isViewMode

  useEffect(() => {
    setMobileSelectionMode(false)
    setSelectedEmails([])
  }, [selectedFolder, data.inboxTab])

  useEffect(() => {
    if (!openSwipeRowId) return
    const handler = (e: globalThis.TouchEvent) => {
      const target = e.target as HTMLElement | null
      if (!target) return
      const swipeRow = target.closest(`[data-swipe-row-id="${openSwipeRowId}"]`)
      if (!swipeRow) setOpenSwipeRowId(null)
    }
    document.addEventListener("touchstart", handler, { passive: true })
    return () => document.removeEventListener("touchstart", handler)
  }, [openSwipeRowId])

  const openMobileXsMoveSheet = useCallback(() => {
    setMobileXsMoreMenuOpen(false)
    window.setTimeout(() => setMobileXsMoveSheetOpen(true), 0)
  }, [])

  const handleMobileXsMoveSheetOpenChange = useCallback((open: boolean) => {
    setMobileXsMoveSheetOpen(open)
    if (!open) {
      setMobileSelectionMode(false)
      setSelectedEmails([])
    }
  }, [])

  const openMobileXsLabelSheet = useCallback(() => {
    setMobileXsMoreMenuOpen(false)
    setSwipeLabelEmailId(null)
    window.setTimeout(() => setMobileXsLabelSheetOpen(true), 0)
  }, [])

  const handleLabelSheetOpenChange = useCallback((open: boolean) => {
    setMobileXsLabelSheetOpen(open)
    if (!open) setSwipeLabelEmailId(null)
  }, [])

  const selectedOnPageCount = useMemo(
    () => pageIds.filter((id) => selectedEmails.includes(id)).length,
    [pageIds, selectedEmails]
  )
  const allPageSelected = pageIds.length > 0 && selectedOnPageCount === pageIds.length
  const somePageSelected = selectedOnPageCount > 0 && !allPageSelected
  const selectAllChecked: boolean | "indeterminate" = allPageSelected
    ? true
    : somePageSelected
      ? "indeterminate"
      : false

  const toggleStar = (id: string) => {
    mailActions.toggleStar(id)
  }

  const toggleImportant = (id: string) => {
    mailActions.toggleImportant(id)
  }

  const toggleSelect = (id: string) => {
    setSelectedEmails(prev =>
      prev.includes(id) ? prev.filter(e => e !== id) : [...prev, id]
    )
  }

  const selectRangeInclusive = (fromId: string, toId: string) => {
    const ids = pageIds
    const i0 = ids.indexOf(fromId)
    const i1 = ids.indexOf(toId)
    if (i0 === -1 || i1 === -1) return
    const lo = Math.min(i0, i1)
    const hi = Math.max(i0, i1)
    const range = ids.slice(lo, hi + 1)
    setSelectedEmails((prev) => [...new Set([...prev, ...range])])
  }

  const handleSelectAllChange = (checked: boolean | "indeterminate") => {
    if (checked === true) {
      setSelectedEmails((prev) => [...new Set([...prev, ...pageIds])])
    } else {
      setSelectedEmails((prev) => prev.filter((id) => !pageIds.includes(id)))
    }
  }

  const mergePageSelection = (subsetOfPageIds: string[]) => {
    setSelectedEmails((prev) => {
      const outsidePage = prev.filter((id) => !pageIds.includes(id))
      return [...new Set([...outsidePage, ...subsetOfPageIds])]
    })
  }

  const selectMenuAll = () => mergePageSelection(pageIds)
  const selectMenuNone = () =>
    setSelectedEmails((prev) => prev.filter((id) => !pageIds.includes(id)))
  const selectMenuRead = () =>
    mergePageSelection(
      listEmails.filter((e) => effectiveRead(e)).map((e) => e.id)
    )
  const selectMenuUnread = () =>
    mergePageSelection(
      listEmails.filter((e) => !effectiveRead(e)).map((e) => e.id)
    )
  const selectMenuStarred = () =>
    mergePageSelection(
      listEmails.filter((e) => effectiveStarred(e)).map((e) => e.id)
    )
  const selectMenuUnstarred = () =>
    mergePageSelection(
      listEmails.filter((e) => !effectiveStarred(e)).map((e) => e.id)
    )

  const handleRowCheckboxClickCapture = (id: string, e: MouseEvent) => {
    if (e.shiftKey && lastSelectionAnchorIdRef.current != null) {
      e.preventDefault()
      e.stopPropagation()
      selectRangeInclusive(lastSelectionAnchorIdRef.current, id)
      lastSelectionAnchorIdRef.current = id
    }
  }

  const bulkTargetIds = useMemo(
    () => pageIds.filter((id) => selectedEmails.includes(id)),
    [pageIds, selectedEmails]
  )
  const hasUnreadInSelection = useMemo(() => {
    for (const id of bulkTargetIds) {
      const email = allEmails.find((e) => e.id === id)
      if (!email) continue
      const isRead =
        readOverrides[id] !== undefined ? readOverrides[id]! : email.read
      if (!isRead) return true
    }
    return false
  }, [bulkTargetIds, readOverrides, allEmails])
  const showBulkToolbar = bulkTargetIds.length > 0

  const labelSheetTargetIds = useMemo(
    () => (swipeLabelEmailId ? [swipeLabelEmailId] : bulkTargetIds),
    [swipeLabelEmailId, bulkTargetIds]
  )

  const clearBulkSelection = (ids: string[]) => {
    setSelectedEmails((prev) => prev.filter((id) => !ids.includes(id)))
  }

  const bulkHideFromList = (ids: string[]) => {
    if (ids.length === 0) return
    mailActions.hideEmails(ids)
    clearBulkSelection(ids)
  }

  const bulkArchive = () => bulkHideFromList(bulkTargetIds)
  const bulkDelete = () => bulkHideFromList(bulkTargetIds)
  const bulkSpam = () => bulkHideFromList(bulkTargetIds)

  const handleEmailsDroppedOnTarget = useCallback(
    (targetId: string, _targetLabel: string, ids: string[]) => {
      if (ids.length === 0) return
      moveEmailsToTarget(ids, targetId)
      setSelectedEmails((prev) => prev.filter((id) => !ids.includes(id)))
    },
    [moveEmailsToTarget]
  )

  useEffect(() => {
    return registerOnDrop(handleEmailsDroppedOnTarget)
  }, [registerOnDrop, handleEmailsDroppedOnTarget])

  const startRowDrag = useCallback(
    (rowId: string, e: DragEvent<HTMLDivElement>) => {
      if (isXs) return
      const inSelection = selectedEmails.includes(rowId)
      const ids =
        inSelection && bulkTargetIds.length > 0 ? bulkTargetIds : [rowId]
      if (e.dataTransfer) {
        e.dataTransfer.effectAllowed = "move"
        try {
          e.dataTransfer.setData("text/plain", ids.join(","))
        } catch {
          /* some browsers throw if called outside dragstart context */
        }
        const ghost = document.createElement("div")
        ghost.style.position = "fixed"
        ghost.style.top = "-1000px"
        ghost.style.left = "-1000px"
        ghost.style.width = "1px"
        ghost.style.height = "1px"
        ghost.style.opacity = "0"
        document.body.appendChild(ghost)
        e.dataTransfer.setDragImage(ghost, 0, 0)
        window.setTimeout(() => {
          if (ghost.parentNode) ghost.parentNode.removeChild(ghost)
        }, 0)
      }
      beginDrag(ids, selectedFolder, e.clientX, e.clientY)
    },
    [beginDrag, isXs, selectedEmails, bulkTargetIds, selectedFolder]
  )

  const bulkMarkRead = () => {
    if (bulkTargetIds.length === 0) return
    setReadOverrides((prev) => {
      const next = { ...prev }
      for (const id of bulkTargetIds) next[id] = true
      return next
    })
  }

  const bulkMarkUnread = () => {
    if (bulkTargetIds.length === 0) return
    setReadOverrides((prev) => {
      const next = { ...prev }
      for (const id of bulkTargetIds) next[id] = false
      return next
    })
  }

  const bulkMoveTo = useCallback(
    (targetId: string) => {
      if (bulkTargetIds.length === 0) return
      moveEmailsToTarget(bulkTargetIds, targetId)
      if (targetId !== "inbox") {
        setSelectedEmails((prev) => prev.filter((id) => !bulkTargetIds.includes(id)))
      }
    },
    [bulkTargetIds, moveEmailsToTarget]
  )

  const openSwipeRowLabelSheet = useCallback((emailId: string) => {
    setSwipeLabelEmailId(emailId)
    setMobileXsLabelSheetOpen(true)
  }, [])

  return {
    selectedEmails,
    setSelectedEmails,
    rowContextMenuOpenedAtRef,
    contextMenuTargetIdsRef,
    lastSelectionAnchorIdRef,
    bulkSelectMenuOpen,
    setBulkSelectMenuOpen,
    mobileSelectionMode,
    setMobileSelectionMode,
    mobileXsMoreMenuOpen,
    setMobileXsMoreMenuOpen,
    mobileXsMoveSheetOpen,
    mobileXsLabelSheetOpen,
    swipeLabelEmailId,
    openSwipeRowId,
    setOpenSwipeRowId,
    touchListSwipeEnabled,
    openMobileXsMoveSheet,
    handleMobileXsMoveSheetOpenChange,
    openMobileXsLabelSheet,
    handleLabelSheetOpenChange,
    selectAllChecked,
    handleSelectAllChange,
    selectMenuAll,
    selectMenuNone,
    selectMenuRead,
    selectMenuUnread,
    selectMenuStarred,
    selectMenuUnstarred,
    toggleStar,
    toggleImportant,
    toggleSelect,
    handleRowCheckboxClickCapture,
    bulkTargetIds,
    hasUnreadInSelection,
    showBulkToolbar,
    labelSheetTargetIds,
    bulkArchive,
    bulkDelete,
    bulkSpam,
    bulkMarkRead,
    bulkMarkUnread,
    bulkMoveTo,
    startRowDrag,
    openSwipeRowLabelSheet,
  }
}

export type EmailListSelection = ReturnType<typeof useEmailListSelection>
