'use client'

import { useState, useTransition, useEffect, useRef } from 'react'
import type { Note } from '@/lib/types'
import { getNoteFeedImage, getNotePlainExcerpt, getNoteDisplayTitle } from '@/lib/note-preview'
import { useLanguage } from '@/lib/i18n'
import { emitNoteChange, type NoteCollectionActions } from '@/lib/note-change-sync'
import { motion, AnimatePresence } from 'motion/react'
import { ChevronRight, MoreHorizontal, Trash2, Archive, Pin, History, Pencil, Sparkles, Loader2, Bell, FolderOpen, FileText } from 'lucide-react'
import { useLabelsQuery } from '@/lib/query-hooks'
import { useSession } from 'next-auth/react'
import { getAISettings } from '@/app/actions/ai-settings'
import { generateNoteIllustrationSvg } from '@/app/actions/note-illustration'
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import { MoveToNotebookPickerPortal } from '@/components/move-to-notebook-picker'
import { deleteNote, toggleArchive, togglePin, updateNote } from '@/app/actions/notes'
import { ReminderDialog } from '@/components/reminder-dialog'
import { useNotebooks } from '@/context/notebooks-context'
import { toast } from 'sonner'
import { fr } from 'date-fns/locale/fr'
import { enUS } from 'date-fns/locale/en-US'
import { formatAbsoluteDateLocalized } from '@/lib/utils/format-localized-date'
import { cn } from '@/lib/utils'
import { useHydrated } from '@/lib/use-hydrated'

type NotesEditorialViewProps = {
  notes: Note[]
  onOpen: (note: Note, readOnly?: boolean) => void
  notebookName?: string
  onOpenHistory?: (note: Note) => void
} & NoteCollectionActions

function formatNoteDate(date: Date | string, language: string): string {
  const d = typeof date === 'string' ? new Date(date) : date
  const locale = language === 'fr' ? fr : enUS
  if (language === 'fa') {
    return formatAbsoluteDateLocalized(d, language, 'd MMM yyyy', locale)
  }
  const month = d.toLocaleDateString('en-US', { month: 'short', timeZone: 'UTC' })
  const day = d.getUTCDate()
  const year = d.getUTCFullYear()
  return `${month.toUpperCase()} ${day}, ${year}`
}

export function EditorialNoteMenu({
  note,
  onOpen,
  onOpenHistory,
  onTogglePin,
  onDeleteNote,
  onArchiveNote,
  onMoveToNotebook,
  onNotePatch,
}: {
  note: Note
  onOpen: (note: Note) => void
  onOpenHistory?: (note: Note) => void
} & NoteCollectionActions) {
  const { t } = useLanguage()
  const { notebooks } = useNotebooks()
  const [, startTransition] = useTransition()
  const [showReminder, setShowReminder] = useState(false)
  const [movePickerOpen, setMovePickerOpen] = useState(false)
  const menuTriggerRef = useRef<HTMLButtonElement>(null)

  const handleDelete = (e: React.MouseEvent) => {
    e.stopPropagation()
    if (onDeleteNote) {
      onDeleteNote(note)
      return
    }
    startTransition(async () => {
      try {
        await deleteNote(note.id, { skipRevalidation: true })
        emitNoteChange({ type: 'deleted', noteId: note.id, notebookId: note.notebookId })
        toast.success(t('notes.deleted') || 'Note supprimée')
      } catch {
        toast.error(t('general.error'))
      }
    })
  }

  const handleArchive = (e: React.MouseEvent) => {
    e.stopPropagation()
    if (onArchiveNote) {
      onArchiveNote(note)
      return
    }
    startTransition(async () => {
      try {
        await toggleArchive(note.id, !note.isArchived, { skipRevalidation: true })
        emitNoteChange({ type: 'updated', note: { ...note, isArchived: !note.isArchived } })
        toast.success(note.isArchived ? (t('notes.unarchived') || 'Désarchivée') : (t('notes.archived') || 'Archivée'))
      } catch {
        toast.error(t('general.error'))
      }
    })
  }

  const handlePin = (e: React.MouseEvent) => {
    e.stopPropagation()
    if (onTogglePin) {
      onTogglePin(note)
      return
    }
    startTransition(async () => {
      try {
        const nextPinned = !note.isPinned
        await togglePin(note.id, nextPinned, { skipRevalidation: true })
        emitNoteChange({ type: 'updated', note: { ...note, isPinned: nextPinned } })
      } catch {
        toast.error(t('general.error'))
      }
    })
  }

  const handleMoveToNotebook = (notebookId: string | null) => {
    if (onMoveToNotebook) {
      onMoveToNotebook(note, notebookId)
      return
    }
    startTransition(async () => {
      try {
        await updateNote(note.id, { notebookId }, { skipRevalidation: true })
        emitNoteChange({ type: 'updated', note: { ...note, notebookId } })
        toast.success(t('notebookSuggestion.movedToNotebook') || 'Note déplacée')
      } catch {
        toast.error(t('general.error'))
      }
    })
  }

  const patchReminder = (reminder: Date | null) => {
    startTransition(async () => {
      try {
        await updateNote(note.id, { reminder }, { skipRevalidation: true })
        const patch = { reminder: reminder?.toISOString() ?? null }
        onNotePatch?.(note.id, patch)
        emitNoteChange({ type: 'updated', note: { ...note, reminder: patch.reminder } })
        setShowReminder(false)
      } catch {
        toast.error(t('general.error'))
      }
    })
  }

  return (
    <>
      <DropdownMenu>
        <DropdownMenuTrigger asChild onClick={e => e.stopPropagation()}>
          <button
            ref={menuTriggerRef}
            className="opacity-0 group-hover:opacity-100 transition-opacity p-1.5 rounded-md hover:bg-muted/60 text-muted-foreground hover:text-foreground"
          >
            <MoreHorizontal size={15} />
          </button>
        </DropdownMenuTrigger>
        <DropdownMenuContent align="end" className="w-52">
          <DropdownMenuItem onClick={e => { e.stopPropagation(); onOpen(note) }}>
            <Pencil className="h-4 w-4 me-2 text-foreground/50" />
            {t('notes.open') || 'Ouvrir'}
          </DropdownMenuItem>
          <DropdownMenuItem onClick={handlePin}>
            <Pin className="h-4 w-4 me-2 text-foreground/50" />
            {note.isPinned ? (t('notes.unpin') || 'Désépingler') : (t('notes.pin') || 'Épingler')}
          </DropdownMenuItem>
          <DropdownMenuItem onClick={handleArchive}>
            <Archive className="h-4 w-4 me-2 text-foreground/50" />
            {note.isArchived ? (t('notes.unarchive') || 'Désarchiver') : (t('notes.archive') || 'Archiver')}
          </DropdownMenuItem>
          {onOpenHistory && (
            <DropdownMenuItem onClick={e => { e.stopPropagation(); onOpenHistory(note) }}>
              <History className="h-4 w-4 me-2 text-foreground/50" />
              {t('notes.history') || 'Historique'}
            </DropdownMenuItem>
          )}

          {/* Rappel */}
          <DropdownMenuItem onClick={e => { e.stopPropagation(); setShowReminder(true) }}>
            <Bell className="h-4 w-4 me-2 text-foreground/50" />
            {note.reminder
              ? (t('reminder.changeReminder') || 'Modifier le rappel')
              : (t('reminder.setReminder') || 'Définir un rappel')}
          </DropdownMenuItem>

          {/* Déplacer vers un carnet */}
          <DropdownMenuItem
            onClick={e => {
              e.stopPropagation()
              setMovePickerOpen(true)
            }}
          >
            <FolderOpen className="h-4 w-4 me-2 text-foreground/50" />
            {t('notebookSuggestion.moveToNotebook') || 'Déplacer vers…'}
          </DropdownMenuItem>

          <DropdownMenuSeparator />
          <DropdownMenuItem onClick={handleDelete} className="text-destructive focus:text-destructive focus:bg-destructive/10">
            <Trash2 className="h-4 w-4 me-2" />
            {t('notes.delete') || 'Supprimer'}
          </DropdownMenuItem>
        </DropdownMenuContent>
      </DropdownMenu>

      <MoveToNotebookPickerPortal
        open={movePickerOpen}
        onOpenChange={setMovePickerOpen}
        anchorRef={menuTriggerRef}
        notebooks={notebooks}
        currentNotebookId={note.notebookId}
        onSelect={handleMoveToNotebook}
        align="end"
        preferDropUp
      />

      {/* ReminderDialog hors du DropdownMenu pour éviter les conflits de portail */}
      <ReminderDialog
        open={showReminder}
        onOpenChange={setShowReminder}
        currentReminder={note.reminder ? new Date(note.reminder) : null}
        onSave={(date) => patchReminder(date)}
        onRemove={() => patchReminder(null)}
      />
    </>
  )
}

/** Deterministic hue from a string — consistent per note */
function stringToHue(s: string): number {
  let h = 0
  for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) & 0xffff
  return h % 360
}

function EditorialThumbnail({
  note,
  title,
  aiIllustrationEnabled,
  onNoteIllustrationGenerated,
}: {
  note: Note
  title: string
  aiIllustrationEnabled: boolean
  onNoteIllustrationGenerated?: (noteId: string) => void | Promise<void>
}) {
  const { t } = useLanguage()
  const [busy, setBusy] = useState(false)
  const img = getNoteFeedImage(note)

  const handleGenerateSvg = async (e: React.MouseEvent) => {
    e.stopPropagation()
    if (!aiIllustrationEnabled || busy || img) return
    setBusy(true)
    try {
      const res = await generateNoteIllustrationSvg(note.id, { skipRevalidation: true })
      if (!res.ok) {
        toast.error(res.error)
      } else {
        toast.success(t('notes.illustrationGenerated') || 'Illustration générée')
        await onNoteIllustrationGenerated?.(note.id)
      }
    } finally {
      setBusy(false)
    }
  }

  return (
    <div className="relative w-full md:w-56 aspect-[4/3] bg-card/80 border border-border overflow-hidden rounded shadow-sm flex-shrink-0 group/thumb">
      {img ? (
        <img
          src={img}
          alt=""
          className="w-full h-full object-cover mix-blend-multiply opacity-80 grayscale contrast-125 hover:grayscale-0 hover:opacity-100 transition-all duration-500"
        />
      ) : note.illustrationSvg ? (
        <div
          className="w-full h-full flex items-center justify-center bg-muted/30 p-2 [&_svg]:max-w-full [&_svg]:max-h-full [&_svg]:w-auto [&_svg]:h-auto"
          // SVG déjà sanitisé côté serveur (note-illustration.ts)
          dangerouslySetInnerHTML={{ __html: note.illustrationSvg }}
          aria-hidden
        />
      ) : (
        <>
          <NoteThumbnailPlaceholder noteId={note.id} />
          {aiIllustrationEnabled && (
            <button
              type="button"
              aria-label={t('notes.generateIllustration') || 'Générer une illustration IA'}
              title={t('notes.generateIllustration') || 'Générer une illustration IA'}
              className="absolute bottom-2 end-2 flex h-9 w-9 items-center justify-center rounded-full border border-border bg-background/95 text-foreground shadow-card-rest backdrop-blur-sm transition-colors hover:bg-accent z-10 opacity-0 group-hover/thumb:opacity-100 md:opacity-100 focus-visible:opacity-100"
              onClick={handleGenerateSvg}
              disabled={busy}
            >
              {busy ? <Loader2 className="h-4 w-4 animate-spin" /> : <Sparkles className="h-4 w-4 text-primary" />}
            </button>
          )}
        </>
      )}
    </div>
  )
}

/** SVG thumbnail for notes without an image — icône document (ref. architectural-grid), pas initiale */
function NoteThumbnailPlaceholder({ noteId }: { noteId: string }) {
  const hue = stringToHue(noteId)

  return (
    <div
      className="h-full w-full flex items-center justify-center relative overflow-hidden"
      style={{ background: `linear-gradient(145deg, hsl(${hue} 25% var(--thumb-lightness-1, 94%)) 0%, hsl(${hue} 18% var(--thumb-lightness-2, 87%)) 100%)` }}
    >
      <svg
        className="absolute inset-0 w-full h-full"
        viewBox="0 0 224 168"
        fill="none"
        aria-hidden
        style={{ color: `hsl(${hue} 30% 60%)` }}
      >
        <circle cx="112" cy="84" r="90" stroke="currentColor" strokeWidth="0.6" opacity="0.25" />
        <circle cx="112" cy="84" r="64" stroke="currentColor" strokeWidth="0.6" opacity="0.2" />
        <circle cx="112" cy="84" r="38" stroke="currentColor" strokeWidth="0.6" opacity="0.15" />
        <line x1="22" y1="84" x2="202" y2="84" stroke="currentColor" strokeWidth="0.4" opacity="0.15" />
        <line x1="112" y1="4" x2="112" y2="164" stroke="currentColor" strokeWidth="0.4" opacity="0.15" />
      </svg>
      <FileText
        size={40}
        strokeWidth={1.25}
        className="relative text-muted-foreground/45"
        style={{ color: `hsl(${hue} 25% 45%)` }}
      />
    </div>
  )
}

function NoteTag({ labelName, allLabels }: { labelName: string; allLabels: any[] }) {
  const labelDef = allLabels?.find(l => l.name === labelName)
  const isAI = labelDef?.type === 'ai'
  
  return (
    <div className="inline-flex items-center gap-1.5 px-2 py-0.5 rounded-md bg-paper dark:bg-white/5 text-[9px] font-bold uppercase tracking-[0.15em] text-muted-foreground border border-border/40">
      {isAI && <Sparkles size={8} className="text-brand-accent" />}
      {labelName}
    </div>
  )
}

export function NotesEditorialView({
  notes,
  onOpen,
  notebookName,
  onOpenHistory,
  onTogglePin,
  onDeleteNote,
  onArchiveNote,
  onMoveToNotebook,
  onNotePatch,
  onNoteIllustrationGenerated,
}: NotesEditorialViewProps) {
  const { t, language } = useLanguage()
  const { data: session } = useSession()
  const { data: allLabels } = useLabelsQuery()
  const hydrated = useHydrated()
  const [aiIllustrationEnabled, setAiIllustrationEnabled] = useState(false)

  useEffect(() => {
    if (!session?.user?.id) {
      setAiIllustrationEnabled(false)
      return
    }
    getAISettings(session.user.id)
      .then((s) => setAiIllustrationEnabled(s.paragraphRefactor !== false))
      .catch(() => setAiIllustrationEnabled(false))
  }, [session?.user?.id])

  return (
    <div className="mx-auto w-full max-w-3xl space-y-8">
      <AnimatePresence>
        {notes.map((note: Note, index: number) => {
          const title = getNoteDisplayTitle(note, t('notes.untitled') || 'Untitled')
          const excerpt = getNotePlainExcerpt(note)
          const dateStr = formatNoteDate(note.createdAt, language)
          const editorialRtl = language === 'fa' || language === 'ar'

          return (
            <motion.article
              key={note.id}
              initial={hydrated ? { opacity: 0, y: 20 } : false}
              animate={{ opacity: 1, y: 0 }}
              transition={hydrated ? { delay: 0.05 * index, duration: 0.6 } : { duration: 0 }}
              className="space-y-4 group cursor-pointer relative pb-8"
              onClick={() => onOpen(note)}
            >
              {/* Date / breadcrumb — isolated bidi so Latin notebook name + Jalali date don’t reorder wrongly */}
              <div
                className={cn('note-date-badge', editorialRtl && 'note-date-badge--locale-rtl')}
                dir={editorialRtl ? 'rtl' : 'ltr'}
              >
                {notebookName ? (
                  <>
                    <bdi className={cn(editorialRtl && 'uppercase tracking-[0.2em]')}>{notebookName}</bdi>
                    <span className="mx-1.5 select-none text-muted-foreground/80" aria-hidden>
                      —
                    </span>
                    <bdi dir="rtl" lang={editorialRtl ? 'fa' : undefined}>
                      {dateStr}
                    </bdi>
                  </>
                ) : (
                  <bdi dir={editorialRtl ? 'rtl' : 'ltr'} lang={editorialRtl ? 'fa' : undefined}>
                    {dateStr}
                  </bdi>
                )}
              </div>

              {/* Actions menu — absolutely positioned at top-right */}
              <div
                className="absolute top-0 end-0 opacity-0 group-hover:opacity-100 transition-opacity"
                onClick={e => e.stopPropagation()}
              >
                <EditorialNoteMenu
                  note={note}
                  onOpen={onOpen}
                  onOpenHistory={onOpenHistory}
                  onTogglePin={onTogglePin}
                  onDeleteNote={onDeleteNote}
                  onArchiveNote={onArchiveNote}
                  onMoveToNotebook={onMoveToNotebook}
                  onNotePatch={onNotePatch}
                />
              </div>

              <h2 className="font-memento-serif text-2xl font-medium text-foreground flex items-center justify-between">
                {title}
                <span className="opacity-0 group-hover:opacity-30 transition-opacity shrink-0">
                  <ChevronRight size={20} />
                </span>
              </h2>

              <div className="flex flex-col md:flex-row gap-8 items-start">
                <EditorialThumbnail
                  note={note}
                  title={title}
                  aiIllustrationEnabled={aiIllustrationEnabled}
                  onNoteIllustrationGenerated={onNoteIllustrationGenerated}
                />
                <div className="space-y-3 flex-1">
                  {note.labels && note.labels.length > 0 && (
                    <div className="flex flex-wrap gap-2">
                      {note.labels.slice(0, 2).map((labelName) => (
                        <NoteTag key={labelName} labelName={labelName} allLabels={allLabels || []} />
                      ))}
                    </div>
                  )}
                  {excerpt ? (
                    <p className="text-[14px] leading-relaxed text-foreground/80 font-light max-w-lg line-clamp-4">
                      {excerpt}
                    </p>
                  ) : (
                    <p className="text-sm italic text-muted-foreground/50">{t('notes.noContent')}</p>
                  )}
                  <span className="text-[11px] text-muted-foreground uppercase tracking-widest font-medium inline-flex items-center gap-1 group-hover:gap-2 transition-all">
                    {t('notes.readMore') || 'Read more'}
                    <ChevronRight size={10} />
                  </span>
                </div>
              </div>
            </motion.article>
          )
        })}
      </AnimatePresence>
    </div>
  )
}
