"use client"

import { useState, useEffect, useRef } from "react"
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
import { Group, Panel, Separator } from "react-resizable-panels"
import { createSupabaseBrowserClient } from "@/lib/supabase/client"
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 { notify } from "@/lib/notify"

interface SharedEntry {
  identifier: string
  entryIdentifier: string
  shareToken: string
  createdAt: string
  expiresAt: string | null
  note: string | null
  noteIsPublic: boolean
  viewCount: number
  lastViewedAt: string | null
  entryTitle: string | null
  entryUrl: string | null
}

function useSharedEntries() {
  const supabaseClient = createSupabaseBrowserClient()

  return useQuery({
    queryKey: ["shared-entries"],
    queryFn: async () => {
      const { data, error } = await supabaseClient
        .from("shared_entries")
        .select("id, entry_id, share_token, created_at, expires_at, note, note_is_public, view_count, last_viewed_at, entries(title, url)")
        .order("created_at", { ascending: false })

      if (error) throw error

      return (data ?? []).map(
        (row) => {
          const entryData = row.entries as unknown as {
            title: string | null
            url: string | null
          } | null

          const rowData = row as Record<string, unknown>

          return {
            identifier: row.id,
            entryIdentifier: row.entry_id,
            shareToken: row.share_token,
            createdAt: row.created_at,
            expiresAt: row.expires_at,
            note: rowData.note as string | null,
            noteIsPublic: (rowData.note_is_public as boolean) ?? false,
            viewCount: (rowData.view_count as number) ?? 0,
            lastViewedAt: rowData.last_viewed_at as string | null,
            entryTitle: entryData?.title ?? null,
            entryUrl: entryData?.url ?? null,
          }
        }
      )
    },
  })
}

function useRevokeShare() {
  const supabaseClient = createSupabaseBrowserClient()
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async (shareIdentifier: string) => {
      const { error } = await supabaseClient
        .from("shared_entries")
        .delete()
        .eq("id", shareIdentifier)

      if (error) throw error
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["shared-entries"] })
      notify("share revoked")
    },
    onError: () => {
      notify("failed to revoke share")
    },
  })
}

function useUpdateShareNote() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async ({ shareToken, note, noteIsPublic }: { shareToken: string; note?: string | null; noteIsPublic?: boolean }) => {
      const payload: Record<string, unknown> = {}
      if (note !== undefined) payload.note = note
      if (noteIsPublic !== undefined) payload.noteIsPublic = noteIsPublic
      const response = await fetch(`/api/share/${shareToken}`, {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(payload),
      })
      if (!response.ok) throw new Error("failed to update share")
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["shared-entries"] })
      notify("share updated")
    },
    onError: () => {
      notify("failed to update share")
    },
  })
}

function isExpired(expiresAt: string | null): boolean {
  if (!expiresAt) return false
  return new Date(expiresAt) < new Date()
}

function ShareRow({
  share,
  isSelected,
  isFocused,
  viewMode,
  onSelect,
}: {
  share: SharedEntry
  isSelected: boolean
  isFocused: boolean
  viewMode: "compact" | "comfortable" | "expanded"
  onSelect: (entryIdentifier: string) => void
}) {
  const [showRevokeConfirm, setShowRevokeConfirm] = useState(false)
  const [isEditingNote, setIsEditingNote] = useState(false)
  const [editedNote, setEditedNote] = useState(share.note ?? "")
  const revokeShare = useRevokeShare()
  const updateNote = useUpdateShareNote()
  const expired = isExpired(share.expiresAt)

  function handleCopyLink() {
    const shareUrl = `${window.location.origin}/shared/${share.shareToken}`
    navigator.clipboard.writeText(shareUrl)
    notify("link copied")
  }

  function handleSaveNote() {
    const trimmedNote = editedNote.trim()
    updateNote.mutate({ shareToken: share.shareToken, note: trimmedNote || null })
    setIsEditingNote(false)
  }

  const sharedDate = new Date(share.createdAt).toLocaleDateString("en-GB", {
    day: "numeric",
    month: "short",
    year: "numeric",
  })

  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
        data-share-list-item
        onClick={() => onSelect(share.entryIdentifier)}
        className={rowClassName}
      >
        <div className="flex items-center gap-2 py-2.5">
          <span className="min-w-0 flex-1 truncate text-text-primary">
            {share.entryTitle ?? "untitled"}
          </span>
          {expired && <span className="shrink-0 text-status-error">expired</span>}
          {share.viewCount > 0 && (
            <span className="shrink-0 text-text-dim">
              {share.viewCount} view{share.viewCount !== 1 ? "s" : ""}
            </span>
          )}
          <span className="shrink-0 text-text-dim">{sharedDate}</span>
        </div>
      </div>
    )
  }

  if (viewMode === "comfortable") {
    return (
      <div
        data-share-list-item
        onClick={() => onSelect(share.entryIdentifier)}
        className={rowClassName}
      >
        <div className="py-2.5">
          <span className="block truncate text-text-primary">
            {share.entryTitle ?? "untitled"}
          </span>
          <div className="mt-0.5 flex items-center gap-2 text-text-dim">
            <span>shared {sharedDate}</span>
            {share.expiresAt && (
              <>
                <span>&middot;</span>
                {expired ? (
                  <span className="text-status-error">expired</span>
                ) : (
                  <span>
                    expires{" "}
                    {new Date(share.expiresAt).toLocaleDateString("en-GB", {
                      day: "numeric",
                      month: "short",
                      year: "numeric",
                    })}
                  </span>
                )}
              </>
            )}
            {share.viewCount > 0 && (
              <>
                <span>&middot;</span>
                <span>{share.viewCount} view{share.viewCount !== 1 ? "s" : ""}</span>
              </>
            )}
            {share.note && (
              <>
                <span>&middot;</span>
                <span className="truncate">{share.note}</span>
              </>
            )}
          </div>
        </div>
      </div>
    )
  }

  return (
    <div
      data-share-list-item
      onClick={() => onSelect(share.entryIdentifier)}
      className={classNames(rowClassName, "flex flex-col gap-1 py-3")}
    >
      <div className="flex items-center justify-between">
        <div className="min-w-0 flex-1">
          <span className="block truncate text-text-primary">
            {share.entryTitle ?? "untitled"}
          </span>
          {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
                type="button"
                onClick={handleSaveNote}
                className="px-2 py-1 text-text-secondary transition-colors hover:text-text-primary"
              >
                save
              </button>
              <button
                type="button"
                onClick={() => setIsEditingNote(false)}
                className="px-2 py-1 text-text-secondary transition-colors hover:text-text-primary"
              >
                cancel
              </button>
            </div>
          ) : share.note ? (
            <p className="truncate text-text-secondary">{share.note}</p>
          ) : null}
          <p className="text-text-dim">
            shared {sharedDate}
            {share.expiresAt && (
              <>
                {" \u00b7 "}
                {expired ? (
                  <span className="text-status-error">expired</span>
                ) : (
                  <>
                    expires{" "}
                    {new Date(share.expiresAt).toLocaleDateString(
                      "en-GB",
                      {
                        day: "numeric",
                        month: "short",
                        year: "numeric",
                      }
                    )}
                  </>
                )}
              </>
            )}
            {share.viewCount > 0 && (
              <>
                {" \u00b7 "}
                {share.viewCount} view{share.viewCount !== 1 ? "s" : ""}
              </>
            )}
            {share.noteIsPublic && share.note && (
              <>
                {" \u00b7 "}
                <span>note is public</span>
              </>
            )}
          </p>
        </div>
      </div>
      <div className="flex items-center gap-2">
        {!expired && (
          <button
            type="button"
            onClick={handleCopyLink}
            className="px-2 py-1 text-text-secondary transition-colors hover:text-text-primary"
          >
            copy link
          </button>
        )}
        <button
          type="button"
          onClick={() => {
            setEditedNote(share.note ?? "")
            setIsEditingNote(true)
          }}
          className="px-2 py-1 text-text-dim transition-colors hover:text-text-secondary"
        >
          {share.note ? "edit note" : "add note"}
        </button>
        {share.note && (
          <button
            type="button"
            onClick={(event) => {
              event.stopPropagation()
              updateNote.mutate({
                shareToken: share.shareToken,
                noteIsPublic: !share.noteIsPublic,
              })
            }}
            className="px-2 py-1 text-text-dim transition-colors hover:text-text-secondary"
          >
            {share.noteIsPublic ? "make note private" : "make note public"}
          </button>
        )}
        {showRevokeConfirm ? (
          <div className="flex items-center gap-1">
            <span className="text-text-dim">revoke?</span>
            <button
              type="button"
              onClick={() => {
                revokeShare.mutate(share.identifier)
                setShowRevokeConfirm(false)
              }}
              className="px-2 py-1 text-status-error transition-colors hover:text-text-primary"
            >
              yes
            </button>
            <button
              type="button"
              onClick={() => setShowRevokeConfirm(false)}
              className="px-2 py-1 text-text-secondary transition-colors hover:text-text-primary"
            >
              no
            </button>
          </div>
        ) : (
          <button
            type="button"
            onClick={() => setShowRevokeConfirm(true)}
            className="px-2 py-1 text-text-secondary transition-colors hover:text-status-error"
          >
            revoke
          </button>
        )}
      </div>
    </div>
  )
}

function SharesList({
  shares,
  selectedEntryIdentifier,
  focusedEntryIdentifier,
  viewMode,
  onSelect,
}: {
  shares: SharedEntry[]
  selectedEntryIdentifier: string | null
  focusedEntryIdentifier: string | null
  viewMode: "compact" | "comfortable" | "expanded"
  onSelect: (entryIdentifier: string) => void
}) {
  const listReference = useRef<HTMLDivElement>(null)

  useEffect(() => {
    if (!focusedEntryIdentifier) return
    const container = listReference.current
    if (!container) return
    const items = container.querySelectorAll("[data-share-list-item]")
    const focusedIndex = shares.findIndex(
      (share) => share.entryIdentifier === focusedEntryIdentifier
    )
    items[focusedIndex]?.scrollIntoView({ block: "nearest" })
  }, [focusedEntryIdentifier, shares])

  if (shares.length === 0) {
    return (
      <div className="flex h-full items-center justify-center text-text-dim">
        no shared entries yet
      </div>
    )
  }

  return (
    <div ref={listReference} className="h-full overflow-auto">
      {shares.map((share) => (
        <ShareRow
          key={share.identifier}
          share={share}
          isSelected={share.entryIdentifier === selectedEntryIdentifier}
          isFocused={share.entryIdentifier === focusedEntryIdentifier}
          viewMode={viewMode}
          onSelect={onSelect}
        />
      ))}
    </div>
  )
}

export function SharesContent() {
  const { data: shares, isLoading } = useSharedEntries()
  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 sharesList = shares ?? []

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

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

  if (isLoading) {
    return <p className="px-6 py-8 text-text-dim">loading shares ...</p>
  }

  const activeShareCount = sharesList.filter(
    (share) => !isExpired(share.expiresAt)
  ).length

  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">shares</h1>
        </div>
        <span className="text-text-dim">
          {activeShareCount} active share{activeShareCount !== 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">
              <SharesList
                shares={sharesList}
                selectedEntryIdentifier={null}
                focusedEntryIdentifier={focusedEntryIdentifier}
                viewMode="expanded"
                onSelect={setSelectedEntryIdentifier}
              />
            </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"
              )}>
                <SharesList
                  shares={sharesList}
                  selectedEntryIdentifier={selectedEntryIdentifier}
                  focusedEntryIdentifier={focusedEntryIdentifier}
                  viewMode="expanded"
                  onSelect={setSelectedEntryIdentifier}
                />
              </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>
  )
}
