"use client"

import {
  startTransition,
  useCallback,
  useEffect,
  useLayoutEffect,
  useMemo,
  useRef,
} from "react"
import type { Email } from "@/lib/email-data"
import { readStateTargets } from "@/lib/mail-thread"
import { threadStoreId } from "@/lib/mail-settings/list-row-id"
import { resolveOpenEmailView } from "@/lib/mail-settings/resolve-open-email"
import {
  DEFAULT_INBOX_TAB,
} from "@/lib/mail-url"
import {
  mailNavVisitKey,
  parseMailNavVisitKey,
} from "@/lib/mail-folder-display"
import {
  escapeHtml,
} from "@/components/gmail/email-list/email-list-helpers"
import type { Contact } from "@/lib/compose-context"
import {
  buildThreadComposePreset,
  withTouchFullscreenComposePreset,
} from "@/lib/thread-compose-preset"
import type { EmailListProps } from "@/components/gmail/email-list/email-list-helpers"
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"
import { useMailUiStore } from "@/lib/stores/mail-ui-store"

export function useEmailListReading(
  props: EmailListProps,
  data: EmailListData,
  labels: EmailListLabels
) {
  const {
    onMailRouteNavigate,
    onSelectFolder,
    onXsViewChromeChange,
  } = props

  const {
    openMailId,
    splitView,
    isViewMode,
    showSplitReadingPane,
    isXs,
    allEmails,
    emailById,
    displayListEmails,
    listPage,
    listPageSize,
    listRowsDep,
    listViewportRef,
    conversationMode,
    setReadOverrides,
    markEmailSeen,
    mailActions,
    moveTargets,
    selectedFolder,
    inboxTab,
    openComposeWithInitial,
  } = data

  const { moveEmailsToTarget } = labels

  const openEmailView = useMemo(() => {
    if (!openMailId) return null
    const resolved = resolveOpenEmailView(
      openMailId,
      allEmails,
      conversationMode
    )
    if (!resolved) return null
    if (resolved.email.labels?.includes("scheduled")) return null
    return {
      email: resolved.email,
      threadRoot: resolved.threadRoot,
      isSingleMessageView: resolved.isSingleMessageView,
    }
  }, [openMailId, allEmails, conversationMode])

  const openEmail = openEmailView?.email ?? null
  const openEmailThreadRoot = openEmailView?.threadRoot ?? null
  const isSingleMessageView = openEmailView?.isSingleMessageView ?? false

  const openMailIndex = useMemo(
    () =>
      openMailId ? displayListEmails.findIndex((e) => e.id === openMailId) : -1,
    [openMailId, displayListEmails]
  )

  // Guard: emailById/setReadOverrides get new refs after each messages refetch — without
  // this guard, mark-read → invalidate → refetch → effect re-runs in a loop.
  const readAppliedForMailRef = useRef<string | null>(null)

  useEffect(() => {
    if (!openMailId) {
      readAppliedForMailRef.current = null
      return
    }
    if (readAppliedForMailRef.current === openMailId) return
    const message = emailById.get(openMailId)
    if (!message) return

    readAppliedForMailRef.current = openMailId
    const targets = readStateTargets(message, conversationMode)
    for (const id of targets) {
      markEmailSeen(id)
    }
    setReadOverrides((prev) => {
      const next = { ...prev }
      for (const id of targets) {
        next[id] = true
      }
      return next
    })
  }, [openMailId, markEmailSeen, emailById, conversationMode, setReadOverrides])

  const navigateToMail = useCallback(
    (id: string | null) => {
      if (id === null) {
        useMailUiStore.getState().requestSuppressSplitAutoOpen()
      }
      startTransition(() => {
        if (id && splitView) {
          const idx = displayListEmails.findIndex((e) => e.id === id)
          if (idx >= 0) {
            const page = Math.floor(idx / listPageSize) + 1
            onMailRouteNavigate({ mailId: id, page })
            return
          }
        }
        onMailRouteNavigate({ mailId: id })
      })
    },
    [splitView, displayListEmails, onMailRouteNavigate, listPageSize]
  )

  useEffect(() => {
    if (!openMailId) return
    const raw = allEmails.find((e) => e.id === openMailId)
    if (raw?.labels?.includes("scheduled")) {
      navigateToMail(null)
    }
  }, [openMailId, allEmails, navigateToMail])

  const pickAdjacentMailId = useCallback(
    (currentId: string) => {
      const idx = displayListEmails.findIndex((e) => e.id === currentId)
      if (idx < 0) return displayListEmails[0]?.id ?? null
      if (idx < displayListEmails.length - 1) return displayListEmails[idx + 1]!.id
      if (idx > 0) return displayListEmails[idx - 1]!.id
      return null
    },
    [displayListEmails]
  )

  const leaveReadingPane = useCallback(() => {
    if (!splitView) {
      navigateToMail(null)
      return
    }
    if (!openMailId) return
    navigateToMail(pickAdjacentMailId(openMailId))
  }, [splitView, openMailId, navigateToMail, pickAdjacentMailId])

  const goBack = useCallback(() => {
    if (splitView) {
      navigateToMail(null)
      return
    }
    navigateToMail(null)
  }, [splitView, navigateToMail])

  const closeViewIfShowingEmail = useCallback(
    (emailId: string) => {
      if (openMailId === emailId) goBack()
    },
    [openMailId, goBack]
  )

  const archiveListRow = useCallback(
    (email: Email) => {
      if (email.labels?.includes("scheduled")) {
        void data.requestArchiveScheduled(email.id)
      } else {
        mailActions.hideEmail(email.id)
        closeViewIfShowingEmail(email.id)
      }
    },
    [closeViewIfShowingEmail, mailActions, data]
  )

  const deleteListRow = useCallback(
    (email: Email) => {
      if (email.labels?.includes("scheduled")) {
        void data.requestDeleteScheduled(email.id)
      } else {
        mailActions.hideEmail(email.id)
        closeViewIfShowingEmail(email.id)
      }
    },
    [closeViewIfShowingEmail, mailActions, data]
  )

  const restoreSnoozedRowToMailbox = useCallback(
    (emailRow: Email) => {
      void data.requestRestoreSnoozedToInbox(emailRow)
      if (emailRow.id.startsWith("snz-")) {
        onSelectFolder?.("inbox")
      } else {
        onSelectFolder?.("scheduled")
      }
      closeViewIfShowingEmail(emailRow.id)
    },
    [
      data,
      closeViewIfShowingEmail,
      onSelectFolder,
    ]
  )

  const handleCategoryInboxTabClick = useCallback(
    (tabId: string) => {
      useMailUiStore.getState().requestSuppressSplitAutoOpen()
      startTransition(() => {
        onMailRouteNavigate({
          inboxTab: tabId,
          page: 1,
          mailId: null,
        })
      })
    },
    [onMailRouteNavigate]
  )

  const handleBreadcrumbNavigate = useCallback(
    (visitKey: string) => {
      if (visitKey === mailNavVisitKey(selectedFolder, inboxTab)) return
      const { folderId, inboxTab: tab } = parseMailNavVisitKey(visitKey)
      startTransition(() => {
        if (folderId === "inbox" && tab && tab !== DEFAULT_INBOX_TAB) {
          onMailRouteNavigate({
            folderId: "inbox",
            inboxTab: tab,
            page: 1,
            mailId: null,
          })
          return
        }
        if (onSelectFolder) {
          onSelectFolder(folderId)
          return
        }
        onMailRouteNavigate({
          folderId,
          inboxTab: DEFAULT_INBOX_TAB,
          page: 1,
          mailId: null,
        })
      })
    },
    [
      selectedFolder,
      inboxTab,
      onMailRouteNavigate,
      onSelectFolder,
    ]
  )

  const goListPrevPage = useCallback(() => {
    if (listPage <= 1) return
    onMailRouteNavigate({ page: listPage - 1 })
  }, [listPage, onMailRouteNavigate])

  const goListNextPage = useCallback(() => {
    if (listPage >= data.totalPages) return
    onMailRouteNavigate({ page: listPage + 1 })
  }, [listPage, data.totalPages, onMailRouteNavigate])

  const goToPrev = useCallback(() => {
    if (openMailIndex > 0) {
      const id = displayListEmails[openMailIndex - 1]!.id
      markEmailSeen(id)
      setReadOverrides(() => ({ [id]: true }))
      navigateToMail(id)
    }
  }, [openMailIndex, displayListEmails, navigateToMail, markEmailSeen, setReadOverrides])

  const goToNext = useCallback(() => {
    if (openMailIndex >= 0 && openMailIndex < displayListEmails.length - 1) {
      const id = displayListEmails[openMailIndex + 1]!.id
      markEmailSeen(id)
      setReadOverrides(() => ({ [id]: true }))
      navigateToMail(id)
    }
  }, [openMailIndex, displayListEmails, navigateToMail, markEmailSeen, setReadOverrides])

  const handleOpenEmail = useCallback(
    (id: string) => {
      const em = allEmails.find((e) => e.id === id)
      if (em?.labels?.includes("scheduled")) return
      markEmailSeen(id)
      setReadOverrides(() => ({ [id]: true }))
      navigateToMail(id)
    },
    [navigateToMail, markEmailSeen, allEmails, setReadOverrides]
  )

  const openDraftInCompose = useCallback(
    (email: Email) => {
      markEmailSeen(email.id)
      setReadOverrides(() => ({ [email.id]: true }))
      const to: Contact[] = email.senderEmail
        ? [{ name: email.sender.trim(), email: email.senderEmail }]
        : []
      const body =
        email.body ??
        (email.preview
          ? `<p style="color:#5f6368">${escapeHtml(email.preview)}</p>`
          : "<p></p>")
      openComposeWithInitial({
        to,
        subject: email.subject,
        bodyHtml: body,
        focusToOnMount: false,
        focusBodyOnMount: true,
      })
    },
    [markEmailSeen, openComposeWithInitial, setReadOverrides]
  )

  const handleRowActivate = useCallback(
    (email: Email) => {
      if (email.labels?.includes("scheduled")) return
      if (email.labels?.includes("drafts")) {
        openDraftInCompose(email)
        return
      }
      handleOpenEmail(email.id)
    },
    [handleOpenEmail, openDraftInCompose]
  )

  const viewModeIsRead = useMemo(() => {
    if (!openEmail) return true
    return openEmail.read
  }, [openEmail])

  const afterSingleMessageRemoved = useCallback(
    (removedId: string) => {
      if (splitView) navigateToMail(pickAdjacentMailId(removedId))
      else navigateToMail(null)
    },
    [splitView, navigateToMail, pickAdjacentMailId]
  )

  const singleArchive = useCallback(() => {
    if (!openMailId) return
    const id = openMailId
    mailActions.hideEmail(id)
    afterSingleMessageRemoved(id)
  }, [openMailId, afterSingleMessageRemoved, mailActions])

  const singleDelete = useCallback(() => {
    if (!openMailId) return
    const id = openMailId
    mailActions.hideEmail(id)
    afterSingleMessageRemoved(id)
  }, [openMailId, afterSingleMessageRemoved, mailActions])

  const singleSpam = useCallback(() => {
    if (!openMailId) return
    const id = openMailId
    mailActions.hideEmail(id)
    afterSingleMessageRemoved(id)
  }, [openMailId, afterSingleMessageRemoved, mailActions])

  const singleNotSpam = useCallback(() => {
    if (!openMailId) return
    const id = openMailId
    mailActions.markNotSpam(id)
    onSelectFolder?.("inbox")
    afterSingleMessageRemoved(id)
  }, [openMailId, afterSingleMessageRemoved, onSelectFolder, mailActions])

  const singleToggleRead = useCallback(() => {
    if (!openMailId) return
    const next = !viewModeIsRead
    setReadOverrides(() => ({ [openMailId]: next }))
  }, [openMailId, viewModeIsRead, setReadOverrides])

  const singleMoveTo = useCallback(
    (targetId: string) => {
      if (!openMailId) return
      moveEmailsToTarget([openMailId], targetId)
      const isSystemHide = ["sent", "drafts", "spam", "trash"].includes(targetId)
      if (isSystemHide || targetId !== "inbox") {
        afterSingleMessageRemoved(openMailId)
      }
    },
    [openMailId, afterSingleMessageRemoved, moveEmailsToTarget]
  )

  const singleReply = useCallback(() => {
    if (!openEmail) return
    openComposeWithInitial(
      withTouchFullscreenComposePreset(buildThreadComposePreset(openEmail, "reply"))
    )
  }, [openEmail, openComposeWithInitial])

  const xsViewChromeCallbacksRef = useRef({
    onArchive: singleArchive,
    onReply: singleReply,
    moveTargets,
    onMoveTo: singleMoveTo,
  })
  xsViewChromeCallbacksRef.current = {
    onArchive: singleArchive,
    onReply: singleReply,
    moveTargets,
    onMoveTo: singleMoveTo,
  }

  useEffect(() => {
    if (!onXsViewChromeChange) return
    if (!isXs || !isViewMode || !openMailId) {
      onXsViewChromeChange(null)
      return
    }
    onXsViewChromeChange({
      onArchive: () => xsViewChromeCallbacksRef.current.onArchive(),
      onReply: () => xsViewChromeCallbacksRef.current.onReply(),
      moveTargets: xsViewChromeCallbacksRef.current.moveTargets,
      onMoveTo: (targetId) =>
        xsViewChromeCallbacksRef.current.onMoveTo(targetId),
    })
    return () => onXsViewChromeChange(null)
  }, [onXsViewChromeChange, isXs, isViewMode, openMailId, moveTargets])

  useEffect(() => {
    if (!splitView) return
    if (useMailUiStore.getState().consumeSuppressSplitAutoOpen()) {
      return
    }
    const firstId = displayListEmails[0]?.id ?? null
    if (!openMailId) {
      if (firstId) navigateToMail(firstId)
      return
    }
    const raw = allEmails.find((e) => e.id === openMailId)
    if (raw?.labels?.includes("scheduled")) {
      navigateToMail(firstId)
      return
    }
    if (!displayListEmails.some((e) => e.id === openMailId)) {
      navigateToMail(firstId)
    }
  }, [
    splitView,
    selectedFolder,
    inboxTab,
    listPage,
    displayListEmails,
    openMailId,
    navigateToMail,
    allEmails,
  ])

  const handleNavigateToLabel = useCallback(
    (label: string) => {
      const folderId =
        data.sidebarNav.emailLabelToSidebarFolderId[label] ?? label
      onSelectFolder?.(folderId)
    },
    [onSelectFolder, data.sidebarNav.emailLabelToSidebarFolderId]
  )

  useLayoutEffect(() => {
    if (!splitView || !openMailId) return
    const scrollActiveRowIntoView = () => {
      const root = listViewportRef.current
      if (!root) return
      const row = root.querySelector<HTMLElement>(
        `[data-email-row-id="${openMailId}"]`
      )
      if (!row) return
      row.scrollIntoView({ block: "nearest", behavior: "smooth" })
    }
    scrollActiveRowIntoView()
    const frame = requestAnimationFrame(scrollActiveRowIntoView)
    return () => cancelAnimationFrame(frame)
  }, [splitView, openMailId, listPage, listRowsDep, listViewportRef])

  useEffect(() => {
    const root = listViewportRef.current
    if (!root) return
    const obs = new IntersectionObserver(
      (entries) => {
        for (const en of entries) {
          if (!en.isIntersecting) continue
          const id = (en.target as HTMLElement).dataset.emailRowId
          if (id) markEmailSeen(id)
        }
      },
      { root, threshold: 0.12, rootMargin: "0px" }
    )

    const observeNewRows = () => {
      root.querySelectorAll<HTMLElement>("[data-email-row-id]").forEach((el) => {
        if (el.dataset.seenObserved === "1") return
        el.dataset.seenObserved = "1"
        obs.observe(el)
      })
    }

    observeNewRows()
    const mutationObserver = new MutationObserver(observeNewRows)
    mutationObserver.observe(root, { childList: true, subtree: true })

    return () => {
      mutationObserver.disconnect()
      obs.disconnect()
    }
  }, [markEmailSeen, listViewportRef])

  useEffect(() => {
    if (!isViewMode && !showSplitReadingPane) return
    const handler = (e: KeyboardEvent) => {
      if (e.key === "Escape") {
        if (!splitView) goBack()
        return
      }
      if (e.key === "ArrowLeft" || e.key === "k") {
        goToPrev()
        return
      }
      if (e.key === "ArrowRight" || e.key === "j") {
        goToNext()
        return
      }
    }
    window.addEventListener("keydown", handler)
    return () => window.removeEventListener("keydown", handler)
  }, [isViewMode, showSplitReadingPane, splitView, goBack, goToPrev, goToNext])

  return {
    openEmail,
    openEmailThreadRoot,
    isSingleMessageView,
    openMailIndex,
    navigateToMail,
    goBack,
    closeViewIfShowingEmail,
    archiveListRow,
    deleteListRow,
    restoreSnoozedRowToMailbox,
    handleCategoryInboxTabClick,
    handleBreadcrumbNavigate,
    goListPrevPage,
    goListNextPage,
    goToPrev,
    goToNext,
    handleOpenEmail,
    handleRowActivate,
    viewModeIsRead,
    singleArchive,
    singleDelete,
    singleSpam,
    singleNotSpam,
    singleToggleRead,
    singleMoveTo,
    singleReply,
    handleNavigateToLabel,
  }
}

export type EmailListReading = ReturnType<typeof useEmailListReading>
