"use client"

import { useCallback, useEffect, useRef, useState } from "react"
import { formatDistanceToNow } from "date-fns"
import { Group, Panel, Separator } from "react-resizable-panels"
import { useAllHighlights } from "@/lib/queries/use-all-highlights"
import {
  useDeleteHighlight,
  useUpdateHighlightNote,
} from "@/lib/queries/use-highlight-mutations"
import { useIsMobile } from "@/lib/hooks/use-is-mobile"
import { useUserInterfaceStore } from "@/lib/stores/user-interface-store"
import { EntryDetailPanel } from "@/app/reader/_components/entry-detail-panel"
import { ErrorBoundary } from "@/app/reader/_components/error-boundary"
import { classNames } from "@/lib/utilities"
import type { HighlightWithEntryContext } from "@/lib/types/highlight"

function groupHighlightsByEntry(
  highlights: HighlightWithEntryContext[]
): Map<string, HighlightWithEntryContext[]> {
  const grouped = new Map<string, HighlightWithEntryContext[]>()

  for (const highlight of highlights) {
    const existing = grouped.get(highlight.entryIdentifier)
    if (existing) {
      existing.push(highlight)
    } else {
      grouped.set(highlight.entryIdentifier, [highlight])
    }
  }

  return grouped
}

function HighlightItem({
  highlight,
  entryIdentifier,
}: {
  highlight: HighlightWithEntryContext
  entryIdentifier: string
}) {
  const [showRemoveConfirm, setShowRemoveConfirm] = useState(false)
  const [isEditingNote, setIsEditingNote] = useState(false)
  const [editedNote, setEditedNote] = useState(highlight.note ?? "")
  const deleteHighlight = useDeleteHighlight()
  const updateNote = useUpdateHighlightNote()

  function handleSaveNote() {
    const trimmedNote = editedNote.trim()
    updateNote.mutate({
      highlightIdentifier: highlight.identifier,
      note: trimmedNote || null,
      entryIdentifier,
    })
    setIsEditingNote(false)
  }

  return (
    <div className="border-l-2 border-text-dim pl-3">
      <p className="text-text-secondary">
        {highlight.highlightedText}
      </p>
      {isEditingNote ? (
        <div className="mt-1 flex items-center gap-2">
          <input
            type="text"
            value={editedNote}
            onChange={(event) => setEditedNote(event.target.value)}
            placeholder="add a note..."
            className="min-w-0 flex-1 border border-border bg-background-primary px-2 py-1 text-text-primary outline-none focus:border-text-dim"
            onKeyDown={(event) => {
              if (event.key === "Enter") handleSaveNote()
              if (event.key === "Escape") setIsEditingNote(false)
            }}
            autoFocus
          />
          <button
            onClick={handleSaveNote}
            className="px-2 py-1 text-text-secondary transition-colors hover:text-text-primary"
          >
            save
          </button>
          <button
            onClick={() => setIsEditingNote(false)}
            className="px-2 py-1 text-text-secondary transition-colors hover:text-text-primary"
          >
            cancel
          </button>
        </div>
      ) : highlight.note ? (
        <p className="mt-1 text-text-dim">
          {highlight.note}
        </p>
      ) : null}
      <div className="mt-1 flex items-center gap-2 text-text-dim">
        <span>
          {formatDistanceToNow(
            new Date(highlight.createdAt),
            { addSuffix: true }
          )}
        </span>
        <button
          type="button"
          onClick={() => {
            setEditedNote(highlight.note ?? "")
            setIsEditingNote(true)
          }}
          className="text-text-secondary transition-colors hover:text-text-primary"
        >
          {highlight.note ? "edit note" : "add note"}
        </button>
        {showRemoveConfirm ? (
          <div className="flex items-center gap-1">
            <span>remove?</span>
            <button
              type="button"
              onClick={() => {
                deleteHighlight.mutate({
                  highlightIdentifier: highlight.identifier,
                  entryIdentifier,
                })
                setShowRemoveConfirm(false)
              }}
              className="text-status-error transition-colors hover:text-text-primary"
            >
              yes
            </button>
            <button
              type="button"
              onClick={() => setShowRemoveConfirm(false)}
              className="text-text-secondary transition-colors hover:text-text-primary"
            >
              no
            </button>
          </div>
        ) : (
          <button
            type="button"
            onClick={() => setShowRemoveConfirm(true)}
            className="text-text-secondary transition-colors hover:text-status-error"
          >
            remove
          </button>
        )}
      </div>
    </div>
  )
}

function HighlightsList({
  groupedByEntry,
  entryIdentifiers,
  selectedEntryIdentifier,
  focusedEntryIdentifier,
  viewMode,
  onSelect,
  lastElementReference,
  hasNextPage,
  isFetchingNextPage,
}: {
  groupedByEntry: Map<string, HighlightWithEntryContext[]>
  entryIdentifiers: string[]
  selectedEntryIdentifier: string | null
  focusedEntryIdentifier: string | null
  viewMode: "compact" | "comfortable" | "expanded"
  onSelect: (entryIdentifier: string) => void
  lastElementReference: (node: HTMLDivElement | null) => (() => void) | undefined
  hasNextPage: boolean
  isFetchingNextPage: boolean
}) {
  const listReference = useRef<HTMLDivElement>(null)

  useEffect(() => {
    if (!focusedEntryIdentifier) return
    const container = listReference.current
    if (!container) return
    const items = container.querySelectorAll("[data-highlight-group-item]")
    const focusedIndex = entryIdentifiers.indexOf(focusedEntryIdentifier)
    items[focusedIndex]?.scrollIntoView({ block: "nearest" })
  }, [focusedEntryIdentifier, entryIdentifiers])

  if (groupedByEntry.size === 0) {
    return (
      <div className="flex h-full items-center justify-center text-text-dim">
        <div className="text-center">
          <p>no highlights yet</p>
          <p className="mt-1 text-xs">
            select text in an entry and click &ldquo;highlight&rdquo; to get started
          </p>
        </div>
      </div>
    )
  }

  return (
    <div ref={listReference} className="h-full overflow-auto">
      {entryIdentifiers.map((entryIdentifier) => {
        const highlights = groupedByEntry.get(entryIdentifier)!
        const firstHighlight = highlights[0]!
        const isSelected = entryIdentifier === selectedEntryIdentifier
        const isFocused = entryIdentifier === focusedEntryIdentifier

        const rowClassName = classNames(
          "cursor-pointer border-b border-border px-4 transition-colors last:border-b-0",
          isSelected
            ? "bg-background-tertiary"
            : isFocused
              ? "bg-background-secondary"
              : "hover:bg-background-secondary",
          isFocused && !isSelected ? "border-l-2 border-l-text-dim" : ""
        )

        if (viewMode === "compact") {
          return (
            <div
              key={entryIdentifier}
              data-highlight-group-item
              onClick={() => onSelect(entryIdentifier)}
              className={rowClassName}
            >
              <div className="flex items-center gap-2 py-2.5">
                <span className="min-w-0 flex-1 truncate text-text-primary">
                  {firstHighlight.entryTitle ?? "untitled"}
                </span>
                <span className="shrink-0 text-text-dim">
                  {highlights.length} highlight{highlights.length !== 1 && "s"}
                </span>
                {firstHighlight.feedTitle && (
                  <span className="shrink-0 text-text-dim">
                    {firstHighlight.feedTitle}
                  </span>
                )}
              </div>
            </div>
          )
        }

        if (viewMode === "comfortable") {
          return (
            <div
              key={entryIdentifier}
              data-highlight-group-item
              onClick={() => onSelect(entryIdentifier)}
              className={rowClassName}
            >
              <div className="py-2.5">
                <span className="block truncate text-text-primary">
                  {firstHighlight.entryTitle ?? "untitled"}
                </span>
                <div className="mt-0.5 flex items-center gap-2 text-text-dim">
                  {firstHighlight.feedTitle && (
                    <span>{firstHighlight.feedTitle}</span>
                  )}
                  <span>
                    {highlights.length} highlight{highlights.length !== 1 && "s"}
                  </span>
                  <span>&middot;</span>
                  <span className="truncate">
                    {firstHighlight.highlightedText}
                  </span>
                </div>
              </div>
            </div>
          )
        }

        return (
          <div
            key={entryIdentifier}
            data-highlight-group-item
            onClick={() => onSelect(entryIdentifier)}
            className={classNames(rowClassName, "py-3")}
          >
            <div className="mb-2 flex items-center gap-2">
              <span className="truncate text-text-primary">
                {firstHighlight.entryTitle ?? "untitled"}
              </span>
              {firstHighlight.feedTitle && (
                <span className="shrink-0 text-text-dim">
                  {firstHighlight.feedTitle}
                </span>
              )}
            </div>
            <div className="space-y-2">
              {highlights.map((highlight) => (
                <HighlightItem
                  key={highlight.identifier}
                  highlight={highlight}
                  entryIdentifier={entryIdentifier}
                />
              ))}
            </div>
          </div>
        )
      })}
      {hasNextPage && (
        <div ref={lastElementReference} className="py-4 text-center">
          {isFetchingNextPage ? (
            <span className="text-text-dim">loading more ...</span>
          ) : (
            <span className="text-text-dim">&nbsp;</span>
          )}
        </div>
      )}
    </div>
  )
}

export function HighlightsContent() {
  const {
    data,
    isLoading,
    hasNextPage,
    fetchNextPage,
    isFetchingNextPage,
  } = useAllHighlights()
  const selectedEntryIdentifier = useUserInterfaceStore(
    (state) => state.selectedEntryIdentifier
  )
  const setSelectedEntryIdentifier = useUserInterfaceStore(
    (state) => state.setSelectedEntryIdentifier
  )
  const focusedEntryIdentifier = useUserInterfaceStore(
    (state) => state.focusedEntryIdentifier
  )
  const setNavigableEntryIdentifiers = useUserInterfaceStore(
    (state) => state.setNavigableEntryIdentifiers
  )
  const focusedPanel = useUserInterfaceStore((state) => state.focusedPanel)
  const isMobile = useIsMobile()

  const lastElementReference = useCallback(
    (node: HTMLDivElement | null) => {
      if (!node || !hasNextPage || isFetchingNextPage) return

      const observer = new IntersectionObserver(
        (entries) => {
          if (entries[0]?.isIntersecting) {
            fetchNextPage()
          }
        },
        { threshold: 0.1 }
      )

      observer.observe(node)
      return () => observer.disconnect()
    },
    [hasNextPage, isFetchingNextPage, fetchNextPage]
  )

  const allHighlights = data?.pages.flat() ?? []
  const groupedByEntry = groupHighlightsByEntry(allHighlights)
  const entryIdentifiers = Array.from(groupedByEntry.keys())

  useEffect(() => {
    setSelectedEntryIdentifier(null)
    setNavigableEntryIdentifiers([])
  }, [setSelectedEntryIdentifier, setNavigableEntryIdentifiers])

  useEffect(() => {
    setNavigableEntryIdentifiers(entryIdentifiers)
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [entryIdentifiers.length, setNavigableEntryIdentifiers])

  if (isLoading) {
    return (
      <div className="flex h-full items-center justify-center text-text-dim">
        loading ...
      </div>
    )
  }

  return (
    <div className="flex h-full flex-col">
      <header className="flex items-center justify-between border-b border-border px-4 py-3">
        <div className="flex items-center gap-3">
          {isMobile && selectedEntryIdentifier && (
            <button
              type="button"
              onClick={() => setSelectedEntryIdentifier(null)}
              className="text-text-secondary transition-colors hover:text-text-primary"
            >
              &larr; back
            </button>
          )}
          <h1 className="text-text-primary">highlights</h1>
        </div>
        <span className="text-text-dim">{allHighlights.length} highlight{allHighlights.length !== 1 && "s"}</span>
      </header>
      <ErrorBoundary>
        {isMobile ? (
          selectedEntryIdentifier ? (
            <div className="flex-1 overflow-hidden">
              <ErrorBoundary>
                <EntryDetailPanel entryIdentifier={selectedEntryIdentifier} />
              </ErrorBoundary>
            </div>
          ) : (
            <div className="flex-1 overflow-hidden">
              <HighlightsList
                groupedByEntry={groupedByEntry}
                entryIdentifiers={entryIdentifiers}
                selectedEntryIdentifier={null}
                focusedEntryIdentifier={focusedEntryIdentifier}
                viewMode="expanded"
                onSelect={setSelectedEntryIdentifier}
                lastElementReference={lastElementReference}
                hasNextPage={hasNextPage ?? false}
                isFetchingNextPage={isFetchingNextPage}
              />
            </div>
          )
        ) : (
          <Group orientation="horizontal" className="flex-1">
            <Panel defaultSize={selectedEntryIdentifier ? 40 : 100} minSize={25}>
              <div data-panel-zone="entryList" className={classNames(
                "h-full",
                focusedPanel === "entryList" ? "border-t-2 border-t-text-dim" : "border-t-2 border-t-transparent"
              )}>
                <HighlightsList
                  groupedByEntry={groupedByEntry}
                  entryIdentifiers={entryIdentifiers}
                  selectedEntryIdentifier={selectedEntryIdentifier}
                  focusedEntryIdentifier={focusedEntryIdentifier}
                  viewMode="expanded"
                  onSelect={setSelectedEntryIdentifier}
                  lastElementReference={lastElementReference}
                  hasNextPage={hasNextPage ?? false}
                  isFetchingNextPage={isFetchingNextPage}
                />
              </div>
            </Panel>
            {selectedEntryIdentifier && (
              <>
                <Separator className="w-px bg-border transition-colors hover:bg-text-dim" />
                <Panel defaultSize={60} minSize={30}>
                  <div data-panel-zone="detailPanel" className={classNames(
                    "h-full",
                    focusedPanel === "detailPanel" ? "border-t-2 border-t-text-dim" : "border-t-2 border-t-transparent"
                  )}>
                    <ErrorBoundary>
                      <EntryDetailPanel entryIdentifier={selectedEntryIdentifier} />
                    </ErrorBoundary>
                  </div>
                </Panel>
              </>
            )}
          </Group>
        )}
      </ErrorBoundary>
    </div>
  )
}
