"use client"

import { useEffect, useMemo, useRef, useState, type CSSProperties, type MouseEvent } from "react"
import { Printer, Download, MoreVertical, Trash2, Tag, Ban, Pencil, GitMerge } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Checkbox } from "@/components/ui/checkbox"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuSub,
  DropdownMenuSubContent,
  DropdownMenuSubTrigger,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { useContactsStore } from "@/lib/contacts/contacts-store"
import { useContactsList } from "@/lib/contacts/use-contacts-list"
import { useDeleteContact, useMergeManyContacts } from "@/lib/api/hooks/use-contact-mutations"
import { useNavStore } from "@/lib/stores/nav-store"
import { searchContacts } from "@/lib/contacts/fuzzy-search"
import { printContacts } from "@/lib/contacts/print-contacts"
import { downloadContactsCsv, downloadContactsVCard } from "@/lib/contacts/export-contacts"
import { fullContactDisplayName } from "@/lib/contacts/types"
import { ContactAvatar } from "@/components/gmail/contacts/contact-avatar"
import type { FullContact } from "@/lib/contacts/types"
import {
  contactsTableGridStyle,
  isContactsColumnVisible,
  useContactsTableColumns,
  type ContactsTableColumn,
} from "@/hooks/use-contacts-table-columns"
import type { ContactsPageView } from "./contacts-app-shell"
import {
  CONTACTS_HEADING_TEXT,
  CONTACTS_ICON_BTN_CLASS,
  CONTACTS_MUTED_TEXT,
  CONTACTS_TABLE_HEADER_CLASS,
  CONTACTS_TABLE_ROW_CLASS,
  CONTACTS_TABLE_HEADER_CHECKBOX_HIT_CLASS,
  CONTACTS_TABLE_TOOLBAR_CLASS,
  CONTACTS_TABLE_STICKY_HEAD_CLASS,
} from "@/lib/contacts-chrome-classes"
import { CONTACTS_MENU_SURFACE_CLASS } from "@/lib/contacts-chrome-classes"
import { cn } from "@/lib/utils"
import { ContactsLoadState } from "@/components/gmail/contacts/contacts-load-state"
import { ContactLabelPickerBlock } from "@/components/gmail/contacts-page/contact-label-picker-block"
import { ContactsBulkEditDialog } from "@/components/gmail/contacts-page/contacts-bulk-edit-dialog"
import { ContactsBulkMergeDialog } from "@/components/gmail/contacts-page/contacts-bulk-merge-dialog"
import { useContactBulkActions } from "@/components/gmail/contacts-page/use-contact-bulk-actions"
import { toast } from "sonner"

const DATA_COLUMNS: Exclude<ContactsTableColumn, "checkbox">[] = [
  "name",
  "email",
  "phone",
  "job",
  "labels",
]

const CONTACTS_ROW_CHECKBOX_HIT_CLASS =
  "flex h-10 w-10 shrink-0 cursor-pointer items-center justify-center rounded-full hover:bg-muted/60 -m-1"

interface ContactsTableProps {
  view: ContactsPageView
  searchQuery: string
  activeLabelId?: string | null
  onOpenContact: (id: string) => void
}

export function ContactsTable({ view, searchQuery, activeLabelId, onOpenContact }: ContactsTableProps) {
  const { visibleColumns, columnLabels } = useContactsTableColumns()
  const gridStyle = contactsTableGridStyle(visibleColumns)
  const { contacts, bookId, isLoading, isError, error, refetch } = useContactsList()
  const softDeleteContact = useContactsStore((s) => s.softDeleteContact)
  const deleteContactMutation = useDeleteContact()
  const mergeManyContactsMutation = useMergeManyContacts()
  const [selectedIds, setSelectedIds] = useState<Set<string>>(() => new Set())
  const [labelPickerQuery, setLabelPickerQuery] = useState("")
  const [bulkEditOpen, setBulkEditOpen] = useState(false)
  const [bulkMergeOpen, setBulkMergeOpen] = useState(false)
  const lastSelectionAnchorIdRef = useRef<string | null>(null)
  const {
    getLabelPresence,
    toggleLabelOnContacts,
    createAndApplyLabel,
    blockContacts,
    applyBulkField,
    resolveLabelVisualById,
    isUpdating,
  } = useContactBulkActions()

  const filteredContacts = useMemo(() => {
    let list = contacts

    if (view === "frequent") {
      list = [...contacts]
        .filter((c) => (c.interactionCount ?? 0) > 0)
        .sort((a, b) => (b.interactionCount ?? 0) - (a.interactionCount ?? 0))
    } else if (view === "other") {
      list = contacts.filter((c) => c.isOtherContact === true)
    } else if (view === "label" && activeLabelId) {
      list = contacts.filter((c) => c.labels?.includes(activeLabelId))
    }

    if (searchQuery.trim()) {
      list = searchContacts(list, searchQuery)
    } else if (view !== "frequent") {
      list = [...list].sort((a, b) => {
        const nameA = fullContactDisplayName(a) || a.emails[0]?.value || ""
        const nameB = fullContactDisplayName(b) || b.emails[0]?.value || ""
        return nameA.localeCompare(nameB, "fr")
      })
    }

    return list
  }, [contacts, view, searchQuery, activeLabelId])

  const filteredIds = useMemo(
    () => new Set(filteredContacts.map((c) => c.id)),
    [filteredContacts]
  )

  const filteredContactIds = useMemo(
    () => filteredContacts.map((c) => c.id),
    [filteredContacts],
  )

  const selectedContacts = useMemo(
    () => filteredContacts.filter((c) => selectedIds.has(c.id)),
    [filteredContacts, selectedIds]
  )

  const selectionCount = selectedContacts.length
  const allFilteredSelected =
    filteredContacts.length > 0 &&
    filteredContacts.every((c) => selectedIds.has(c.id))
  const someFilteredSelected =
    filteredContacts.some((c) => selectedIds.has(c.id)) && !allFilteredSelected

  useEffect(() => {
    setSelectedIds(new Set())
    lastSelectionAnchorIdRef.current = null
  }, [view, activeLabelId])

  useEffect(() => {
    setSelectedIds((prev) => {
      const next = new Set([...prev].filter((id) => filteredIds.has(id)))
      return next.size === prev.size ? prev : next
    })
  }, [filteredIds])

  const labelRows = useNavStore((s) => s.labelRows)
  const availableLabelRows = useMemo(
    () => labelRows.filter((r) => r.enabled !== false),
    [labelRows],
  )
  const activeLabelName = activeLabelId
    ? labelRows.find((l) => l.id === activeLabelId)?.label
    : null

  const viewTitle = view === "frequent"
    ? "Contacts fréquents"
    : view === "other"
      ? "Autres contacts"
      : view === "label" && activeLabelName
        ? activeLabelName
        : `Contacts (${contacts.length})`

  function toggleContact(id: string, checked: boolean) {
    setSelectedIds((prev) => {
      const next = new Set(prev)
      if (checked) next.add(id)
      else next.delete(id)
      return next
    })
    lastSelectionAnchorIdRef.current = id
  }

  function toggleContactInSelection(id: string) {
    setSelectedIds((prev) => {
      const next = new Set(prev)
      if (next.has(id)) next.delete(id)
      else next.add(id)
      return next
    })
    lastSelectionAnchorIdRef.current = id
  }

  function selectRangeInclusive(fromId: string, toId: string) {
    const i0 = filteredContactIds.indexOf(fromId)
    const i1 = filteredContactIds.indexOf(toId)
    if (i0 === -1 || i1 === -1) return
    const lo = Math.min(i0, i1)
    const hi = Math.max(i0, i1)
    setSelectedIds(new Set(filteredContactIds.slice(lo, hi + 1)))
  }

  function handleShiftSelection(id: string) {
    const anchor = lastSelectionAnchorIdRef.current
    if (anchor == null) {
      setSelectedIds(new Set([id]))
    } else {
      selectRangeInclusive(anchor, id)
    }
    lastSelectionAnchorIdRef.current = id
  }

  function handleContactRowClick(
    id: string,
    e: Pick<MouseEvent, "shiftKey" | "metaKey" | "ctrlKey" | "preventDefault">,
  ) {
    if (e.shiftKey) {
      e.preventDefault()
      handleShiftSelection(id)
      return
    }
    if (e.metaKey || e.ctrlKey) {
      e.preventDefault()
      toggleContactInSelection(id)
      return
    }
    onOpenContact(id)
  }

  function handleContactCheckboxClickCapture(id: string, e: MouseEvent) {
    if (!e.shiftKey) return
    e.preventDefault()
    e.stopPropagation()
    handleShiftSelection(id)
  }

  function toggleSelectAll(checked: boolean) {
    if (checked) {
      setSelectedIds(new Set(filteredContacts.map((c) => c.id)))
      lastSelectionAnchorIdRef.current = filteredContacts[0]?.id ?? null
    } else {
      setSelectedIds(new Set())
      lastSelectionAnchorIdRef.current = null
    }
  }

  function handleDeleteSelected() {
    if (selectionCount === 0) return
    for (const contact of selectedContacts) {
      softDeleteContact(contact, "Supprimé manuellement")
      deleteContactMutation.mutate({ path: contact.id })
    }
    setSelectedIds(new Set())
  }

  function handleMergeSelected(primaryId: string) {
    if (!bookId) {
      toast.error("Carnet de contacts introuvable")
      return
    }
    if (selectedContacts.length < 2) return

    mergeManyContactsMutation.mutate(
      {
        bookId,
        contacts: selectedContacts,
        primaryId,
      },
      {
        onSuccess: () => {
          toast.success("Contacts fusionnés")
          setBulkMergeOpen(false)
          setSelectedIds(new Set())
        },
        onError: (err) => {
          const msg =
            err instanceof Error && err.message
              ? err.message
              : "Impossible de fusionner ces contacts"
          toast.error(msg)
        },
      },
    )
  }

  function handleExportVcf() {
    if (selectionCount === 0) return
    const filename =
      selectionCount === 1
        ? `${sanitizeExportName(selectedContacts[0])}.vcf`
        : "contacts.vcf"
    downloadContactsVCard(selectedContacts, filename)
  }

  function handleExportCsv() {
    if (selectionCount === 0) return
    const filename =
      selectionCount === 1
        ? `${sanitizeExportName(selectedContacts[0])}.csv`
        : "contacts.csv"
    downloadContactsCsv(selectedContacts, filename)
  }

  return (
    <div className="px-3 py-4 sm:px-6">
      <div className={CONTACTS_TABLE_STICKY_HEAD_CLASS}>
        <div className={CONTACTS_TABLE_TOOLBAR_CLASS}>
        <h1 className={cn("min-w-0 flex-1 truncate text-xl font-normal sm:text-2xl", CONTACTS_HEADING_TEXT)}>
          {viewTitle}
        </h1>
        <div className="flex shrink-0 items-center gap-1">
          {selectionCount > 0 && (
            <span
              aria-live="polite"
              className={cn(
                "mr-1 hidden text-sm whitespace-nowrap sm:inline",
                CONTACTS_MUTED_TEXT,
              )}
            >
              {selectionCount} sélectionné{selectionCount > 1 ? "s" : ""}
            </span>
          )}
          {selectionCount > 0 && (
            <>
              <Button
                type="button"
                variant="ghost"
                size="sm"
                className={cn("hidden h-9 rounded-full px-3 sm:inline-flex", CONTACTS_ICON_BTN_CLASS)}
                onClick={() => setBulkEditOpen(true)}
              >
                <Pencil className="mr-1.5 h-4 w-4" />
                Édition de masse
              </Button>

              <Button
                type="button"
                variant="ghost"
                size="sm"
                className={cn("hidden h-9 rounded-full px-3 sm:inline-flex", CONTACTS_ICON_BTN_CLASS)}
                disabled={selectionCount < 2}
                onClick={() => setBulkMergeOpen(true)}
              >
                <GitMerge className="mr-1.5 h-4 w-4" />
                Fusionner
              </Button>

              <DropdownMenu
                onOpenChange={(open) => {
                  if (!open) setLabelPickerQuery("")
                }}
              >
                <DropdownMenuTrigger asChild>
                  <Button
                    type="button"
                    variant="ghost"
                    size="icon"
                    className={cn("h-9 w-9 rounded-full", CONTACTS_ICON_BTN_CLASS)}
                    aria-label="Ajouter ou retirer des libellés"
                  >
                    <Tag className="h-5 w-5" />
                  </Button>
                </DropdownMenuTrigger>
                <DropdownMenuContent
                  align="end"
                  data-contacts-menu-surface
                  className={cn(
                    CONTACTS_MENU_SURFACE_CLASS,
                    "flex max-h-72 min-w-[260px] flex-col overflow-hidden p-0 py-0",
                  )}
                >
                  <ContactLabelPickerBlock
                    query={labelPickerQuery}
                    onQueryChange={setLabelPickerQuery}
                    labelRows={availableLabelRows}
                    resolveLabelVisual={resolveLabelVisualById}
                    Item={DropdownMenuItem}
                    getLabelPresence={(labelId) =>
                      getLabelPresence(selectedContacts, labelId)
                    }
                    onToggleLabel={(labelId) =>
                      toggleLabelOnContacts(selectedContacts, labelId)
                    }
                    onCreateLabel={(labelText) => {
                      createAndApplyLabel(selectedContacts, labelText)
                      setLabelPickerQuery("")
                    }}
                  />
                </DropdownMenuContent>
              </DropdownMenu>
            </>
          )}

          <Button
            type="button"
            variant="ghost"
            size="icon"
            className={cn("h-9 w-9 rounded-full", CONTACTS_ICON_BTN_CLASS)}
            onClick={() => printContacts(filteredContacts, viewTitle)}
            aria-label="Imprimer"
          >
            <Printer className="h-5 w-5" />
          </Button>

          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button
                type="button"
                variant="ghost"
                size="icon"
                className={cn("h-9 w-9 rounded-full disabled:opacity-40", CONTACTS_ICON_BTN_CLASS)}
                disabled={selectionCount === 0}
                aria-label="Exporter la sélection"
              >
                <Download className="h-5 w-5" />
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent
              align="end"
              data-contacts-menu-surface
              className={cn("w-52", CONTACTS_MENU_SURFACE_CLASS)}
            >
              <DropdownMenuItem onClick={handleExportVcf}>
                Exporter au format vCard (.vcf)
              </DropdownMenuItem>
              <DropdownMenuItem onClick={handleExportCsv}>
                Exporter au format CSV (.csv)
              </DropdownMenuItem>
            </DropdownMenuContent>
          </DropdownMenu>

          <Button
            type="button"
            variant="ghost"
            size="icon"
            className={cn("h-9 w-9 rounded-full disabled:opacity-40", CONTACTS_ICON_BTN_CLASS)}
            disabled={selectionCount === 0}
            onClick={handleDeleteSelected}
            aria-label="Supprimer la sélection"
          >
            <Trash2 className="h-5 w-5" />
          </Button>

          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button
                type="button"
                variant="ghost"
                size="icon"
                className={cn("h-9 w-9 rounded-full", CONTACTS_ICON_BTN_CLASS)}
                aria-label="Plus d'actions"
              >
                <MoreVertical className="h-5 w-5" />
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent
              align="end"
              data-contacts-menu-surface
              className={cn("w-56 overflow-visible", CONTACTS_MENU_SURFACE_CLASS)}
            >
              {selectionCount > 0 && (
                <>
                  <DropdownMenuSub>
                    <DropdownMenuSubTrigger className="[&>svg:last-child]:text-muted-foreground">
                      <Tag className="mr-2 h-4 w-4 text-muted-foreground" />
                      Ajouter / Retirer des libellés
                    </DropdownMenuSubTrigger>
                    <DropdownMenuSubContent
                      data-contacts-menu-surface
                      className={cn(
                        CONTACTS_MENU_SURFACE_CLASS,
                        "flex max-h-72 min-w-[260px] flex-col overflow-hidden p-0 py-0",
                      )}
                    >
                      <ContactLabelPickerBlock
                        query={labelPickerQuery}
                        onQueryChange={setLabelPickerQuery}
                        labelRows={availableLabelRows}
                        resolveLabelVisual={resolveLabelVisualById}
                        Item={DropdownMenuItem}
                        getLabelPresence={(labelId) =>
                          getLabelPresence(selectedContacts, labelId)
                        }
                        onToggleLabel={(labelId) =>
                          toggleLabelOnContacts(selectedContacts, labelId)
                        }
                        onCreateLabel={(labelText) => {
                          createAndApplyLabel(selectedContacts, labelText)
                          setLabelPickerQuery("")
                        }}
                      />
                    </DropdownMenuSubContent>
                  </DropdownMenuSub>
                  <DropdownMenuItem onClick={() => setBulkEditOpen(true)}>
                    <Pencil className="mr-2 h-4 w-4 text-muted-foreground" />
                    Édition de masse
                  </DropdownMenuItem>
                  <DropdownMenuItem
                    onClick={() => setBulkMergeOpen(true)}
                    disabled={selectionCount < 2}
                  >
                    <GitMerge className="mr-2 h-4 w-4 text-muted-foreground" />
                    Fusionner
                  </DropdownMenuItem>
                  <DropdownMenuItem onClick={() => blockContacts(selectedContacts)}>
                    <Ban className="mr-2 h-4 w-4 text-muted-foreground" />
                    Bloquer
                  </DropdownMenuItem>
                  <DropdownMenuSeparator />
                </>
              )}
              <DropdownMenuItem
                onClick={() => toggleSelectAll(true)}
                disabled={filteredContacts.length === 0}
              >
                Tout sélectionner
              </DropdownMenuItem>
              <DropdownMenuItem
                onClick={() => setSelectedIds(new Set())}
                disabled={selectionCount === 0}
              >
                Désélectionner tout
              </DropdownMenuItem>
            </DropdownMenuContent>
          </DropdownMenu>
        </div>
        </div>

        <div
          className={CONTACTS_TABLE_HEADER_CLASS}
          style={gridStyle}
        >
          {isContactsColumnVisible(visibleColumns, "checkbox") && (
            <span className={CONTACTS_TABLE_HEADER_CHECKBOX_HIT_CLASS}>
              <Checkbox
                checked={allFilteredSelected ? true : someFilteredSelected ? "indeterminate" : false}
                onCheckedChange={(checked) => toggleSelectAll(checked === true)}
                aria-label="Tout sélectionner"
              />
            </span>
          )}
          {DATA_COLUMNS.map((column) =>
            isContactsColumnVisible(visibleColumns, column) ? (
              <span key={column} className="flex min-h-8 items-center">
                {columnLabels[column]}
              </span>
            ) : null
          )}
        </div>
      </div>

      {filteredContacts.map((contact) => (
        <ContactTableRow
          key={contact.id}
          contact={contact}
          visibleColumns={visibleColumns}
          gridStyle={gridStyle}
          selected={selectedIds.has(contact.id)}
          onToggleSelect={(checked) => toggleContact(contact.id, checked)}
          onRowClick={(e) => handleContactRowClick(contact.id, e)}
          onCheckboxClickCapture={(e) => handleContactCheckboxClickCapture(contact.id, e)}
        />
      ))}

      {(isLoading || isError) && (
        <ContactsLoadState
          isLoading={isLoading}
          isError={isError}
          error={error}
          onRetry={refetch}
        />
      )}

      {!isLoading && !isError && filteredContacts.length === 0 && (
        <div className="py-12 text-center text-sm text-muted-foreground">
          Aucun contact trouvé
        </div>
      )}

      <ContactsBulkEditDialog
        open={bulkEditOpen}
        onOpenChange={setBulkEditOpen}
        contacts={selectedContacts}
        onApply={(field, value) => applyBulkField(selectedContacts, field, value)}
        isApplying={isUpdating}
      />

      <ContactsBulkMergeDialog
        open={bulkMergeOpen}
        onOpenChange={setBulkMergeOpen}
        contacts={selectedContacts}
        onMerge={handleMergeSelected}
        isMerging={mergeManyContactsMutation.isPending}
      />
    </div>
  )
}

function sanitizeExportName(contact: FullContact): string {
  const name = fullContactDisplayName(contact) || contact.emails[0]?.value || "contact"
  return name.replace(/[/\\?%*:|"<>]/g, "-").trim() || "contact"
}

function ContactTableRow({
  contact,
  visibleColumns,
  gridStyle,
  selected,
  onToggleSelect,
  onRowClick,
  onCheckboxClickCapture,
}: {
  contact: FullContact
  visibleColumns: ContactsTableColumn[]
  gridStyle: CSSProperties
  selected: boolean
  onToggleSelect: (checked: boolean) => void
  onRowClick: (e: Pick<MouseEvent, "shiftKey" | "metaKey" | "ctrlKey" | "preventDefault">) => void
  onCheckboxClickCapture: (e: MouseEvent<HTMLSpanElement>) => void
}) {
  const displayName = fullContactDisplayName(contact)
  const name = displayName || contact.emails[0]?.value || contact.phones[0]?.value || "?"
  const labelRows = useNavStore((s) => s.labelRows)

  return (
    <div
      role="button"
      tabIndex={0}
      onClick={onRowClick}
      onKeyDown={(e) => {
        if (e.key !== "Enter" && e.key !== " ") return
        e.preventDefault()
        onRowClick(e)
      }}
      className={cn(
        CONTACTS_TABLE_ROW_CLASS,
        "cursor-pointer",
        selected && "bg-mail-nav-selected",
      )}
      style={gridStyle}
    >
      {isContactsColumnVisible(visibleColumns, "checkbox") && (
        <span
          className={CONTACTS_ROW_CHECKBOX_HIT_CLASS}
          onClick={(e) => e.stopPropagation()}
          onClickCapture={onCheckboxClickCapture}
          onKeyDown={(e) => e.stopPropagation()}
        >
          <Checkbox
            checked={selected}
            onCheckedChange={(checked) => onToggleSelect(checked === true)}
            aria-label={`Sélectionner ${name}`}
          />
        </span>
      )}

      {isContactsColumnVisible(visibleColumns, "name") && (
        <span className="flex min-w-0 items-center gap-2 sm:gap-3">
          <ContactAvatar contact={contact} name={name} size="xs" />
          <span className="min-w-0 flex-1">
            <span className="block truncate text-foreground">{name}</span>
            {!isContactsColumnVisible(visibleColumns, "email") && contact.emails[0]?.value && (
              <span className="block truncate text-xs text-muted-foreground">{contact.emails[0].value}</span>
            )}
          </span>
        </span>
      )}

      {isContactsColumnVisible(visibleColumns, "email") && (
        <span className="truncate text-foreground">{contact.emails[0]?.value || ""}</span>
      )}

      {isContactsColumnVisible(visibleColumns, "phone") && (
        <span className="truncate text-foreground">{contact.phones[0]?.value || ""}</span>
      )}

      {isContactsColumnVisible(visibleColumns, "job") && (
        <span className="truncate text-foreground">
          {[contact.jobTitle, contact.company].filter(Boolean).join(", ")}
        </span>
      )}

      {isContactsColumnVisible(visibleColumns, "labels") && (
        <span className="flex flex-wrap gap-1">
          {contact.labels?.map((labelId) => {
            const row = labelRows.find((l) => l.id === labelId)
            return row ? (
              <span
                key={labelId}
                className="inline-flex rounded border border-border px-1.5 py-0.5 text-[11px] text-foreground"
              >
                {row.label}
              </span>
            ) : null
          })}
        </span>
      )}
    </div>
  )
}
