'use client'

import { useCallback, useEffect, useState, useTransition } from 'react'
import {
  DndContext,
  type DragEndEvent,
  KeyboardSensor,
  PointerSensor,
  closestCenter,
  useSensor,
  useSensors,
} from '@dnd-kit/core'
import {
  SortableContext,
  arrayMove,
  verticalListSortingStrategy,
  sortableKeyboardCoordinates,
  useSortable,
} from '@dnd-kit/sortable'
import { CSS } from '@dnd-kit/utilities'
import { Note, NOTE_COLORS, NoteColor } from '@/lib/types'
import { cn } from '@/lib/utils'
import { NoteInlineEditor } from '@/components/note-inline-editor'
import { useLanguage } from '@/lib/i18n'
import { getNoteDisplayTitle } from '@/lib/note-preview'
import { updateFullOrderWithoutRevalidation, createNote, deleteNote } from '@/app/actions/notes'
import {
  GripVertical,
  Hash,
  ListChecks,
  Pin,
  FileText,
  Clock,
  Plus,
  Loader2,
  Trash2,
} from 'lucide-react'
import { Button } from '@/components/ui/button'
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog'
import { toast } from 'sonner'
import { formatDistanceToNow } from 'date-fns'
import { fr } from 'date-fns/locale/fr'
import { enUS } from 'date-fns/locale/en-US'

interface NotesTabsViewProps {
  notes: Note[]
  onEdit?: (note: Note, readOnly?: boolean) => void
  currentNotebookId?: string | null
}

// Color accent strip for each note
const COLOR_ACCENT: Record<NoteColor, string> = {
  default: 'bg-primary',
  red: 'bg-red-400',
  orange: 'bg-orange-400',
  yellow: 'bg-amber-400',
  green: 'bg-emerald-400',
  teal: 'bg-teal-400',
  blue: 'bg-sky-400',
  purple: 'bg-violet-400',
  pink: 'bg-fuchsia-400',
  gray: 'bg-gray-400',
}

// Background tint gradient for selected note panel
const COLOR_PANEL_BG: Record<NoteColor, string> = {
  default: 'from-background to-background',
  red: 'from-red-50/60 dark:from-red-950/20 to-background',
  orange: 'from-orange-50/60 dark:from-orange-950/20 to-background',
  yellow: 'from-amber-50/60 dark:from-amber-950/20 to-background',
  green: 'from-emerald-50/60 dark:from-emerald-950/20 to-background',
  teal: 'from-teal-50/60 dark:from-teal-950/20 to-background',
  blue: 'from-sky-50/60 dark:from-sky-950/20 to-background',
  purple: 'from-violet-50/60 dark:from-violet-950/20 to-background',
  pink: 'from-fuchsia-50/60 dark:from-fuchsia-950/20 to-background',
  gray: 'from-gray-50/60 dark:from-gray-900/20 to-background',
}

const COLOR_ICON: Record<NoteColor, string> = {
  default: 'text-primary',
  red: 'text-red-500',
  orange: 'text-orange-500',
  yellow: 'text-amber-500',
  green: 'text-emerald-500',
  teal: 'text-teal-500',
  blue: 'text-sky-500',
  purple: 'text-violet-500',
  pink: 'text-fuchsia-500',
  gray: 'text-gray-500',
}

function getColorKey(note: Note): NoteColor {
  return (typeof note.color === 'string' && note.color in NOTE_COLORS
    ? note.color
    : 'default') as NoteColor
}

function getDateLocale(language: string) {
  if (language === 'fr') return fr;
  if (language === 'fa') return require('date-fns/locale').faIR;
  return enUS;
}

// ─── Sortable List Item ───────────────────────────────────────────────────────

function SortableNoteListItem({
  note,
  selected,
  onSelect,
  onDelete,
  reorderLabel,
  deleteLabel,
  language,
  untitledLabel,
}: {
  note: Note
  selected: boolean
  onSelect: () => void
  onDelete: () => void
  reorderLabel: string
  deleteLabel: string
  language: string
  untitledLabel: string
}) {
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
    id: note.id,
  })

  const style = {
    transform: CSS.Transform.toString(transform),
    transition,
    zIndex: isDragging ? 50 : undefined,
  }

  const ck = getColorKey(note)
  const title = getNoteDisplayTitle(note, untitledLabel)
  const snippet =
    note.type === 'checklist'
      ? (note.checkItems?.map((i) => i.text).join(' · ') || '').substring(0, 150)
      : (note.content || '').substring(0, 150)

  const dateLocale = getDateLocale(language)
  const timeAgo = formatDistanceToNow(new Date(note.updatedAt), {
    addSuffix: true,
    locale: dateLocale,
  })

  return (
    <div
      ref={setNodeRef}
      style={style}
      className={cn(
        'group relative flex cursor-pointer select-none items-stretch gap-0 rounded-xl transition-all duration-150',
        'border',
        selected
          ? 'border-primary/20 bg-primary/5 dark:bg-primary/10 shadow-sm'
          : 'border-transparent hover:border-border/60 hover:bg-muted/50',
        isDragging && 'opacity-80 shadow-xl ring-2 ring-primary/30'
      )}
      onClick={onSelect}
      role="option"
      aria-selected={selected}
    >
      {/* Color accent bar */}
      <div
        className={cn(
          'w-1 shrink-0 rounded-s-xl transition-all duration-200',
          selected ? COLOR_ACCENT[ck] : 'bg-transparent group-hover:bg-border/40'
        )}
      />

      {/* Drag handle */}
      <button
        type="button"
        className="flex cursor-grab items-center px-1.5 text-muted-foreground/30 opacity-0 transition-opacity group-hover:opacity-100 active:cursor-grabbing"
        aria-label={reorderLabel}
        {...attributes}
        {...listeners}
        onClick={(e) => e.stopPropagation()}
      >
        <GripVertical className="h-3.5 w-3.5" />
      </button>

      {/* Note type icon */}
      <div className="flex items-center py-4 pe-1">
        {note.type === 'checklist' ? (
          <ListChecks
            className={cn(
              'h-4 w-4 shrink-0 transition-colors',
              selected ? COLOR_ICON[ck] : 'text-muted-foreground/50 group-hover:text-muted-foreground'
            )}
          />
        ) : (
          <FileText
            className={cn(
              'h-4 w-4 shrink-0 transition-colors',
              selected ? COLOR_ICON[ck] : 'text-muted-foreground/50 group-hover:text-muted-foreground'
            )}
          />
        )}
      </div>

      {/* Text content */}
      <div className="min-w-0 flex-1 py-3.5 pe-3">
        <div className="flex items-center gap-2">
          <p
            className={cn(
              'truncate text-sm font-medium transition-colors',
              selected ? 'text-foreground' : 'text-foreground/80 group-hover:text-foreground'
            )}
          >
            {title}
          </p>
          {note.isPinned && (
            <Pin className="h-3 w-3 shrink-0 fill-current text-primary" aria-label="Épinglée" />
          )}
        </div>
        {snippet && (
          <p className="mt-0.5 truncate text-xs text-muted-foreground/70">{snippet}</p>
        )}
        <div className="mt-1.5 flex items-center gap-2">
          <span className="flex items-center gap-1 text-[11px] text-muted-foreground/50">
            <Clock className="h-2.5 w-2.5" />
            {timeAgo}
          </span>
          {Array.isArray(note.labels) && note.labels.length > 0 && (
            <>
              <span className="text-muted-foreground/30">·</span>
              <div className="flex items-center gap-1">
                <Hash className="h-2.5 w-2.5 text-muted-foreground/40" />
                <span className="truncate text-[11px] text-muted-foreground/50">
                  {note.labels.slice(0, 2).join(', ')}
                  {note.labels.length > 2 && ` +${note.labels.length - 2}`}
                </span>
              </div>
            </>
          )}
        </div>
      </div>

      {/* Delete button - visible on hover */}
      <button
        type="button"
        onClick={(e) => {
          e.stopPropagation()
          onDelete()
        }}
        className="flex items-center px-2 text-red-500/60 opacity-0 transition-opacity group-hover:opacity-100 hover:text-red-600"
        aria-label={deleteLabel}
        title={deleteLabel}
      >
        <Trash2 className="h-4 w-4" />
      </button>
    </div>
  )
}

// ─── Main Component ───────────────────────────────────────────────────────────

export function NotesTabsView({ notes, onEdit, currentNotebookId }: NotesTabsViewProps) {
  const { t, language } = useLanguage()
  const [items, setItems] = useState<Note[]>(notes)
  const [selectedId, setSelectedId] = useState<string | null>(null)
  const [isCreating, startCreating] = useTransition()
  const [noteToDelete, setNoteToDelete] = useState<Note | null>(null)

  useEffect(() => {
    // Only reset when notes are added or removed, NOT on content/field changes
    // Field changes arrive through onChange -> setItems already
    setItems((prev) => {
      const prevIds = prev.map((n) => n.id).join(',')
      const incomingIds = notes.map((n) => n.id).join(',')
      if (prevIds === incomingIds) {
        // Same set of notes: merge only structural fields (pin, color, archive)
        return prev.map((p) => {
          const fresh = notes.find((n) => n.id === p.id)
          if (!fresh) return p
          // Use fresh labels from server if they've changed (e.g., global label deletion)
          const labelsChanged = JSON.stringify(fresh.labels?.sort()) !== JSON.stringify(p.labels?.sort())
          return {
            ...fresh,
            title: p.title,
            content: p.content,
            // Always use server labels if different (for global label changes)
            labels: labelsChanged ? fresh.labels : p.labels
          }
        })
      }
      // Different set (add/remove): full sync
      return notes
    })
  }, [notes])

  useEffect(() => {
    if (items.length === 0) {
      setSelectedId(null)
      return
    }
    setSelectedId((prev) =>
      prev && items.some((n) => n.id === prev) ? prev : items[0].id
    )
  }, [items])

  // Scroll to top of sidebar on note change handled by NoteInlineEditor internally

  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 6 } }),
    useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
  )

  const handleDragEnd = useCallback(
    async (event: DragEndEvent) => {
      const { active, over } = event
      if (!over || active.id === over.id) return
      const oldIndex = items.findIndex((n) => n.id === active.id)
      const newIndex = items.findIndex((n) => n.id === over.id)
      if (oldIndex < 0 || newIndex < 0) return
      const reordered = arrayMove(items, oldIndex, newIndex)
      setItems(reordered)
      try {
        await updateFullOrderWithoutRevalidation(reordered.map((n) => n.id))
      } catch {
        setItems(notes)
        toast.error(t('notes.moveFailed'))
      }
    },
    [items, notes, t]
  )

  const selected = items.find((n) => n.id === selectedId) ?? null
  const colorKey = selected ? getColorKey(selected) : 'default'

  /** Create a new blank note, add it to the sidebar and select it immediately */
  const handleCreateNote = () => {
    startCreating(async () => {
      try {
        const newNote = await createNote({ 
          content: '', 
          title: undefined,
          notebookId: currentNotebookId || undefined,
          skipRevalidation: true 
        })
        if (!newNote) return
        setItems((prev) => [newNote, ...prev])
        setSelectedId(newNote.id)
      } catch {
        toast.error(t('notes.createFailed') || 'Impossible de créer la note')
      }
    })
  }

  if (items.length === 0) {
    return (
      <div
        className="flex min-h-[240px] flex-col items-center justify-center rounded-2xl border border-dashed border-border/80 bg-muted/20 px-6 py-12 text-center"
        data-testid="notes-grid-tabs-empty"
      >
        <p className="max-w-md text-sm text-muted-foreground">{t('notes.emptyStateTabs')}</p>
      </div>
    )
  }

  return (
    <div
      className="flex min-h-0 flex-1 gap-0 overflow-hidden rounded-2xl border border-border/60 shadow-sm"
      style={{ height: 'max(360px, min(85vh, calc(100vh - 9rem)))' }}
      data-testid="notes-grid-tabs"
    >
      {/* ── Left sidebar: note list ── */}
      <div className="flex w-72 shrink-0 flex-col border-r border-border/60 bg-muted/20">
        {/* Sidebar header with note count + new note button */}
        <div className="border-b border-border/40 px-3 py-2.5">
          <div className="flex items-center justify-between">
            <span className="text-xs font-semibold uppercase tracking-wider text-muted-foreground/60">
              {t('notes.title')}
              <span className="ms-2 rounded-full bg-primary/10 px-1.5 py-0.5 text-[10px] font-medium text-primary">
                {items.length}
              </span>
            </span>
            <Button
              variant="ghost"
              size="sm"
              className="h-7 w-7 p-0 text-muted-foreground hover:text-foreground"
              onClick={handleCreateNote}
              disabled={isCreating}
              title={t('notes.newNote') || 'Nouvelle note'}
            >
              {isCreating
                ? <Loader2 className="h-3.5 w-3.5 animate-spin" />
                : <Plus className="h-3.5 w-3.5" />}
            </Button>
          </div>
        </div>

        {/* Scrollable note list */}
        <div
          className="flex-1 overflow-y-auto overscroll-contain p-2"
          role="listbox"
          aria-label={t('notes.viewTabs')}
        >
          <DndContext
            id="notes-tabs-dnd"
            sensors={sensors}
            collisionDetection={closestCenter}
            onDragEnd={handleDragEnd}
          >
            <SortableContext
              items={items.map((n) => n.id)}
              strategy={verticalListSortingStrategy}
            >
              <div className="flex flex-col gap-0.5">
                {items.map((note) => (
                  <SortableNoteListItem
                    key={note.id}
                    note={note}
                    selected={note.id === selectedId}
                    onSelect={() => setSelectedId(note.id)}
                    onDelete={() => setNoteToDelete(note)}
                    reorderLabel={t('notes.reorderTabs')}
                    deleteLabel={t('notes.delete')}
                    language={language}
                    untitledLabel={t('notes.untitled')}
                  />
                ))}
              </div>
            </SortableContext>
          </DndContext>
        </div>
      </div>

      {/* ── Right content panel — always in edit mode ── */}
      {selected ? (
        <div
          className={cn(
            'flex min-w-0 flex-1 flex-col overflow-hidden bg-gradient-to-br',
            COLOR_PANEL_BG[colorKey]
          )}
        >
          <NoteInlineEditor
            key={selected.id}
            note={selected}
            colorKey={colorKey}
            defaultPreviewMode={true}
            onChange={(noteId, fields) => {
              setItems((prev) =>
                prev.map((n) => (n.id === noteId ? { ...n, ...fields } : n))
              )
            }}
            onDelete={(noteId) => {
              setItems((prev) => prev.filter((n) => n.id !== noteId))
              setSelectedId((prev) => (prev === noteId ? null : prev))
            }}
            onArchive={(noteId) => {
              setItems((prev) => prev.filter((n) => n.id !== noteId))
              setSelectedId((prev) => (prev === noteId ? null : prev))
            }}
          />
        </div>
      ) : (
        <div className="flex flex-1 items-center justify-center text-muted-foreground/40">
          <p className="text-sm">{t('notes.selectNote') || 'Sélectionnez une note'}</p>
        </div>
      )}

      {/* Delete Confirmation Dialog */}
      <Dialog open={!!noteToDelete} onOpenChange={() => setNoteToDelete(null)}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>{t('notes.confirmDeleteTitle') || t('notes.delete')}</DialogTitle>
            <DialogDescription>
              {t('notes.confirmDelete') || 'Are you sure you want to delete this note?'}
              {noteToDelete && (
                <span className="mt-2 block font-medium text-foreground">
                  "{getNoteDisplayTitle(noteToDelete, t('notes.untitled'))}"
                </span>
              )}
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <Button variant="outline" onClick={() => setNoteToDelete(null)}>
              {t('common.cancel')}
            </Button>
            <Button
              variant="destructive"
              onClick={async () => {
                if (!noteToDelete) return
                try {
                  await deleteNote(noteToDelete.id)
                  setItems((prev) => prev.filter((n) => n.id !== noteToDelete.id))
                  setSelectedId((prev) => (prev === noteToDelete.id ? null : prev))
                  setNoteToDelete(null)
                  toast.success(t('notes.deleted'))
                } catch {
                  toast.error(t('notes.deleteFailed'))
                }
              }}
            >
              {t('notes.delete')}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  )
}

