'use client'

import { useState, useEffect, useCallback, useRef, useTransition, useMemo } from 'react'
import { useSearchParams, useRouter } from 'next/navigation'
import dynamic from 'next/dynamic'
import { Note } from '@/lib/types'
import { getAllNotes, searchNotes, enableNoteHistory, getNoteById, createNote } from '@/app/actions/notes'
import { NotesMainSection, type NotesViewMode } from '@/components/notes-main-section'
import { NotesEditorialView } from '@/components/notes-editorial-view'

import { MemoryEchoNotification } from '@/components/memory-echo-notification'
import { NotebookSuggestionToast } from '@/components/notebook-suggestion-toast'
import { Button } from '@/components/ui/button'
import { Plus, ArrowUpDown, Search, Sparkles } from 'lucide-react'
import { useNoteRefresh } from '@/context/NoteRefreshContext'
import { useRefresh } from '@/lib/use-refresh'
import { useReminderCheck } from '@/hooks/use-reminder-check'
import { useAutoLabelSuggestion } from '@/hooks/use-auto-label-suggestion'
import { useNotebooks } from '@/context/notebooks-context'
import { cn } from '@/lib/utils'
import { useLanguage } from '@/lib/i18n'
import { useEditorUI } from '@/context/editor-ui-context'
import { NoteHistoryModal } from '@/components/note-history-modal'
import { toast } from 'sonner'
import { AnimatePresence, motion } from 'motion/react'

type SortOrder = 'newest' | 'oldest' | 'alpha'

const NoteEditor = dynamic(
  () => import('@/components/note-editor').then(m => ({ default: m.NoteEditor })),
  { ssr: false }
)
const BatchOrganizationDialog = dynamic(
  () => import('@/components/batch-organization-dialog').then(m => ({ default: m.BatchOrganizationDialog })),
  { ssr: false }
)
const AutoLabelSuggestionDialog = dynamic(
  () => import('@/components/auto-label-suggestion-dialog').then(m => ({ default: m.AutoLabelSuggestionDialog })),
  { ssr: false }
)

type InitialSettings = {
  showRecentNotes: boolean
  notesViewMode: 'masonry' | 'tabs' | 'list'
  noteHistory: boolean
  noteHistoryMode: 'manual' | 'auto'
}

interface HomeClientProps {
  initialNotes: Note[]
  initialSettings: InitialSettings
}

export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
  const searchParams = useSearchParams()
  const router = useRouter()
  const { t } = useLanguage()

  const [notes, setNotes] = useState<Note[]>(initialNotes)
  const [pinnedNotes, setPinnedNotes] = useState<Note[]>(
    initialNotes.filter(n => n.isPinned)
  )
  const [notesViewMode, setNotesViewMode] = useState<NotesViewMode>(initialSettings.notesViewMode)
  const [noteHistoryMode] = useState<'manual' | 'auto'>(initialSettings.noteHistoryMode)
  const [editingNote, setEditingNote] = useState<{ note: Note; readOnly?: boolean } | null>(null)
  const [isLoading, setIsLoading] = useState(false)
  const [notebookSuggestion, setNotebookSuggestion] = useState<{ noteId: string; content: string } | null>(null)
  const [batchOrganizationOpen, setBatchOrganizationOpen] = useState(false)
  const [historyOpen, setHistoryOpen] = useState(false)
  const [historyNote, setHistoryNote] = useState<Note | null>(null)
  const [isCreating, startCreating] = useTransition()
  const [sortOrder, setSortOrder] = useState<SortOrder>('newest')
  const [showSortMenu, setShowSortMenu] = useState(false)
  const [showInlineSearch, setShowInlineSearch] = useState(false)
  const [inlineSearchQuery, setInlineSearchQuery] = useState('')
  const inlineSearchRef = useRef<HTMLInputElement>(null)
  const notesRef = useRef(notes)
  notesRef.current = notes
  const { refreshKey, triggerRefresh } = useNoteRefresh()
  const { refreshNotes } = useRefresh()
  const { labels, notebooks } = useNotebooks()
  const { setControls } = useEditorUI()

  const { shouldSuggest: shouldSuggestLabels, notebookId: suggestNotebookId, dismiss: dismissLabelSuggestion } = useAutoLabelSuggestion()
  const [autoLabelOpen, setAutoLabelOpen] = useState(false)

  useEffect(() => {
    if (shouldSuggestLabels && suggestNotebookId) {
      setAutoLabelOpen(true)
    }
  }, [shouldSuggestLabels, suggestNotebookId])

  // Sidebar carnet / inbox: forceList → liste éditoriale + fermer l'éditeur plein écran (comme la ref. architectural-grid)
  useEffect(() => {
    const forceList = searchParams.get('forceList')
    if (forceList !== '1') return
    setNotesViewMode(prev => (prev === 'tabs' ? 'masonry' : prev))
    setEditingNote(null)
    const params = new URLSearchParams(searchParams.toString())
    params.delete('forceList')
    const newUrl = params.toString() ? `/?${params.toString()}` : '/'
    router.replace(newUrl, { scroll: false })
  }, [searchParams, router])

  const notebookFilter = searchParams.get('notebook')
  const handleNoteCreated = useCallback((note: Note) => {
    setNotes((prevNotes) => {
      const notebookFilter = searchParams.get('notebook')
      const labelFilter = searchParams.get('labels')?.split(',').filter(Boolean) || []
      const colorFilter = searchParams.get('color')
      const search = searchParams.get('search')?.trim() || null

      if (notebookFilter && note.notebookId !== notebookFilter) return prevNotes
      if (!notebookFilter && note.notebookId) return prevNotes

      if (labelFilter.length > 0) {
        const noteLabels = note.labels || []
        if (!noteLabels.some((label: string) => labelFilter.includes(label))) return prevNotes
      }

      if (colorFilter) {
        const labelNamesWithColor = labels
          .filter((label: any) => label.color === colorFilter)
          .map((label: any) => label.name)
        const noteLabels = note.labels || []
        if (!noteLabels.some((label: string) => labelNamesWithColor.includes(label))) return prevNotes
      }

      if (search) {
        router.refresh()
        return prevNotes
      }

      const isPinned = note.isPinned || false
      const pinnedNotes = prevNotes.filter(n => n.isPinned)
      const unpinnedNotes = prevNotes.filter(n => !n.isPinned)

      if (isPinned) {
        return [note, ...pinnedNotes, ...unpinnedNotes]
      } else {
        return [...pinnedNotes, note, ...unpinnedNotes]
      }
    })

    if (!note.notebookId) {
      const wordCount = (note.content || '').trim().split(/\s+/).filter(w => w.length > 0).length
      if (wordCount >= 20) {
        setNotebookSuggestion({ noteId: note.id, content: note.content || '' })
      }
    }
  }, [searchParams, labels, router])

  // Always fetch fresh from server — avoids stale state after a save regardless of
  // whether the notes list has re-fetched yet.
  const handleOpenNoteFresh = useCallback(async (noteId: string, readOnly = false) => {
    const note = await getNoteById(noteId)
    if (note) setEditingNote({ note, readOnly })
  }, [])

  const handleAddNote = () => {
    startCreating(async () => {
      try {
        const newNote = await createNote({
          content: '',
          type: 'richtext',
          title: undefined,
          notebookId: notebookFilter || undefined,
          skipRevalidation: true
        })
        if (!newNote) return
        handleNoteCreated(newNote)
        setEditingNote({ note: newNote, readOnly: false })
      } catch {
        toast.error(t('notes.createFailed') || 'Failed to create note')
      }
    })
  }

  const handleOpenHistory = useCallback((note: Note) => {
    setHistoryNote(note)
    setHistoryOpen(true)
  }, [])

  const handleEnableHistory = useCallback(async (noteId: string) => {
    await enableNoteHistory(noteId)
    setNotes((prev) => prev.map((n) => (n.id === noteId ? { ...n, historyEnabled: true } : n)))
    setPinnedNotes((prev) => prev.map((n) => (n.id === noteId ? { ...n, historyEnabled: true } : n)))
    setEditingNote((prev) => (prev?.note.id === noteId ? { ...prev, note: { ...prev.note, historyEnabled: true } } : prev))
    setHistoryNote((prev) => (prev?.id === noteId ? { ...prev, historyEnabled: true } : prev))
  }, [])

  const handleHistoryRestored = useCallback((restored: Note) => {
    setNotes((prev) => prev.map((n) => (n.id === restored.id ? { ...n, ...restored } : n)))
    setPinnedNotes((prev) => prev.map((n) => (n.id === restored.id ? { ...n, ...restored } : n)))
    setEditingNote((prev) => (prev?.note.id === restored.id ? { ...prev, note: restored } : prev))
    setHistoryNote((prev) => (prev?.id === restored.id ? { ...prev, ...restored } : prev))
  }, [])

  const handleSizeChange = useCallback((noteId: string, size: 'small' | 'medium' | 'large') => {
    setNotes(prev => prev.map(n => n.id === noteId ? { ...n, size } : n))
    setPinnedNotes(prev => prev.map(n => n.id === noteId ? { ...n, size } : n))
  }, [])

  useReminderCheck(notes)

  // Garder openNote dans l'URL tant que l'éditeur est ouvert → le sidebar peut surligner la note (comme activeNoteId dans la ref.)
  useEffect(() => {
    const openNoteId = searchParams.get('openNote')
    if (!openNoteId) return

    let cancelled = false
    const run = async () => {
      // Always fetch fresh data from DB to avoid showing stale content after a save.
      // notesRef.current can be stale if the notes list hasn't re-fetched yet when the
      // user closes and re-opens the note quickly after saving.
      const note = await getNoteById(openNoteId)
      if (cancelled || !note) return
      setEditingNote({ note, readOnly: false })
    }
    run()
    return () => {
      cancelled = true
    }
  }, [searchParams])

  useEffect(() => {
    const handler = (e: Event) => {
      const { name } = (e as CustomEvent).detail
      if (!name) return
      const removeLabel = (note: Note) => {
        const currentLabels = note.labels || []
        const updated = currentLabels.filter((l) => l.toLowerCase() !== name.toLowerCase())
        if (updated.length === currentLabels.length) return note
        return { ...note, labels: updated.length > 0 ? updated : null }
      }
      setNotes((prev) => prev.map(removeLabel))
      setPinnedNotes((prev) => prev.map(removeLabel))
    }
    window.addEventListener('label-deleted', handler)
    return () => window.removeEventListener('label-deleted', handler)
  }, [])

  const prevRefreshKey = useRef(refreshKey)

  useEffect(() => {
    const search = searchParams.get('search')?.trim() || null
    const labelFilter = searchParams.get('labels')?.split(',').filter(Boolean) || []
    const colorFilter = searchParams.get('color')
    const notebook = searchParams.get('notebook')
    const semanticMode = searchParams.get('semantic') === 'true'

    const isBackgroundRefresh = refreshKey > prevRefreshKey.current
    prevRefreshKey.current = refreshKey

    const hasActiveFilter = search || labelFilter.length > 0 || colorFilter

    const load = async () => {
      if (!isBackgroundRefresh) {
        setIsLoading(true)
      }
      let allNotes = search
        ? await searchNotes(search, semanticMode, notebook || undefined)
        : await getAllNotes(false, notebook || undefined)

      const sharedOnly = searchParams.get('shared') === '1'
      
      if (sharedOnly) {
        allNotes = allNotes.filter((note: any) => note._isShared)
      } else if (!notebook && !search) {
        allNotes = allNotes.filter((note: any) => !note.notebookId && !note._isShared)
      }

      if (labelFilter.length > 0) {
        allNotes = allNotes.filter((note: any) =>
          note.labels?.some((label: string) => labelFilter.includes(label))
        )
      }

      if (colorFilter) {
        const labelNamesWithColor = labels
          .filter((label: any) => label.color === colorFilter)
          .map((label: any) => label.name)
        allNotes = allNotes.filter((note: any) =>
          note.labels?.some((label: string) => labelNamesWithColor.includes(label))
        )
      }

      setNotes(prev => {
        const localSizeMap = new Map(prev.map(n => [n.id, n.size]))
        return allNotes.map(n => ({ ...n, size: localSizeMap.get(n.id) ?? n.size }))
      })
      setPinnedNotes(allNotes.filter((n: any) => n.isPinned))
      setIsLoading(false)
    }

    if (refreshKey > 0 || hasActiveFilter) {
      const cancelled = { value: false }
      load().then(() => { if (cancelled.value) return })
      return () => { cancelled.value = true }
    } else {
      let filtered = initialNotes
      const sharedOnly = searchParams.get('shared') === '1'
      if (notebook) {
        filtered = initialNotes.filter((n: any) => n.notebookId === notebook && !n._isShared)
      } else if (sharedOnly) {
        filtered = initialNotes.filter((n: any) => n._isShared)
      } else {
        filtered = initialNotes.filter((n: any) => !n.notebookId && !n._isShared)
      }
      setNotes(prev => {
        const localSizeMap = new Map(prev.map(n => [n.id, n.size]))
        return filtered.map(n => ({ ...n, size: localSizeMap.get(n.id) ?? n.size }))
      })
      setPinnedNotes(filtered.filter(n => n.isPinned))
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [searchParams, refreshKey])

  const currentNotebook = notebooks.find((n: any) => n.id === searchParams.get('notebook'))

  useEffect(() => {
    setControls({
      isTabsMode: notesViewMode === 'tabs',
      openNoteComposer: () => handleAddNote(),
    })
    return () => setControls(null)
  }, [notesViewMode, setControls])

  // Apply sort order to notes
  const sortedNotes = useMemo(() => {
    const sorted = [...notes]
    if (sortOrder === 'newest') sorted.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
    if (sortOrder === 'oldest') sorted.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime())
    if (sortOrder === 'alpha') sorted.sort((a, b) => (a.title || '').localeCompare(b.title || ''))
    return sorted
  }, [notes, sortOrder])

  const sortedPinnedNotes = useMemo(() => {
    return sortedNotes.filter(n => n.isPinned)
  }, [sortedNotes])

  const sortLabels: Record<SortOrder, string> = {
    newest: t('sidebar.sortNewest') || 'Plus récentes',
    oldest: t('sidebar.sortOldest') || 'Plus anciennes',
    alpha: t('sidebar.sortAlpha') || 'A → Z',
  }

  const isTabs = notesViewMode === 'tabs'
  const isEditorialMode = !isTabs

  const handleEditorClose = useCallback(() => {
    setEditingNote(null)
    const params = new URLSearchParams(searchParams.toString())
    params.delete('openNote')
    const qs = params.toString()
    router.replace(qs ? `/?${qs}` : '/', { scroll: false })
    // Invalidate notes cache and trigger refresh
    refreshNotes(searchParams.get('notebook') || null)
  }, [refreshNotes, router, searchParams])

  // Called by NoteEditor when a save succeeds — update local state immediately
  // so the user sees fresh data if they reopen the note before getAllNotes() completes
  const handleNoteSaved = useCallback((savedNote: Note) => {
    setNotes(prev => prev.map(n => n.id === savedNote.id ? { ...n, ...savedNote } : n))
    setPinnedNotes(prev => prev.map(n => n.id === savedNote.id ? { ...n, ...savedNote } : n))
    setEditingNote(prev => prev?.note.id === savedNote.id ? { ...prev, note: savedNote } : prev)
    // Refresh sidebar note titles so the new title appears immediately
    refreshNotes(savedNote.notebookId || null)
  }, [refreshNotes])

  return (
    <div
      className={cn(
        'flex w-full min-h-0 flex-1 flex-col',
        isTabs ? 'gap-3 py-1' : 'h-full'
      )}
    >
      {editingNote ? (
        <NoteEditor
          note={editingNote.note}
          readOnly={editingNote.readOnly}
          onClose={handleEditorClose}
          onNoteSaved={handleNoteSaved}
          fullPage
        />
      ) : (
        <div className="flex-1 overflow-y-auto min-h-0">
          <div className={cn(
            'px-12 pt-12 pb-8 flex flex-col gap-6',
            isEditorialMode ? 'sticky top-0 bg-background/90 backdrop-blur-md z-30' : ''
          )}>
            <div className="flex justify-between items-start">
              <h1 className="font-memento-serif text-4xl font-medium tracking-tight text-foreground leading-tight pr-12">
                {currentNotebook ? currentNotebook.name : (searchParams.get('shared') === '1' ? 'Partagées avec moi' : t('notes.title'))}
              </h1>
            </div>

            <div className="flex items-center justify-between border-b border-foreground/5 pb-4">
              <div className="flex items-center gap-6">
                <button
                  onClick={handleAddNote}
                  disabled={isCreating}
                  className="flex items-center gap-2 text-[13px] text-foreground font-medium hover:opacity-70 transition-opacity"
                >
                  <Plus size={16} />
                  <span>{t('notes.newNote') || 'Add Note'}</span>
                </button>

                {/* Inline search — toggles an input within the toolbar */}
                {showInlineSearch ? (
                  <div className="flex items-center gap-2">
                    <Search size={14} className="text-muted-foreground shrink-0" />
                    <input
                      ref={inlineSearchRef}
                      autoFocus
                      type="text"
                      value={inlineSearchQuery}
                      onChange={e => {
                        const q = e.target.value
                        setInlineSearchQuery(q)
                        const params = new URLSearchParams(searchParams.toString())
                        if (q.trim()) {
                          params.set('search', q)
                        } else {
                          params.delete('search')
                        }
                        router.push(`/?${params.toString()}`)
                      }}
                      onBlur={() => {
                        if (!inlineSearchQuery) {
                          setShowInlineSearch(false)
                        }
                      }}
                      onKeyDown={e => {
                        if (e.key === 'Escape') {
                          setShowInlineSearch(false)
                          setInlineSearchQuery('')
                          const params = new URLSearchParams(searchParams.toString())
                          params.delete('search')
                          router.push(`/?${params.toString()}`)
                        }
                      }}
                      placeholder={t('search.placeholder') || 'Rechercher...'}
                      className="w-48 bg-transparent border-b border-foreground/20 focus:border-foreground outline-none text-[13px] text-foreground placeholder:text-muted-foreground/50 py-0.5 transition-colors"
                    />
                    {inlineSearchQuery && (
                      <button
                        onClick={() => {
                          setShowInlineSearch(false)
                          setInlineSearchQuery('')
                          const params = new URLSearchParams(searchParams.toString())
                          params.delete('search')
                          router.push(`/?${params.toString()}`)
                        }}
                        className="text-muted-foreground hover:text-foreground transition-colors"
                      >
                        <span className="text-[11px]">×</span>
                      </button>
                    )}
                  </div>
                ) : (
                  <button
                    onClick={() => {
                      setShowInlineSearch(true)
                      setTimeout(() => inlineSearchRef.current?.focus(), 50)
                    }}
                    className="flex items-center gap-2 text-[13px] text-foreground font-medium hover:opacity-70 transition-opacity"
                  >
                    <Search size={16} />
                    <span>{t('notes.search') || 'Search'}</span>
                  </button>
                )}

                {!searchParams.get('notebook') && searchParams.get('shared') !== '1' && (
                  <button
                    onClick={() => setBatchOrganizationOpen(true)}
                    className="flex items-center gap-2 text-[13px] text-foreground font-medium hover:opacity-70 transition-opacity"
                  >
                    <Sparkles size={16} />
                    <span>Réorganiser les notes</span>
                  </button>
                )}
              </div>
              <button
                onClick={() => setSortOrder(s => s === 'newest' ? 'oldest' : s === 'oldest' ? 'alpha' : 'newest')}
                className="flex items-center gap-2 text-[13px] text-foreground font-medium hover:opacity-70 transition-opacity"
              >
                <ArrowUpDown size={16} />
                <span>{sortLabels[sortOrder]}</span>
              </button>
            </div>
          </div>

          <div className="px-12 flex-1 pb-20">
            {isLoading ? (
              <div className="text-center py-8 text-muted-foreground">{t('general.loading')}</div>
            ) : isTabs ? (
              <NotesMainSection
                viewMode={notesViewMode}
                notes={sortedNotes}
                onEdit={(note, readOnly) => setEditingNote({ note, readOnly })}
                onSizeChange={handleSizeChange}
                currentNotebookId={searchParams.get('notebook')}
                noteHistoryMode={noteHistoryMode}
                onOpenHistory={handleOpenHistory}
                onEnableHistory={handleEnableHistory}
                onNoteCreated={handleNoteCreated}
              />
            ) : (
              <div className="max-w-3xl space-y-16">
                {sortedPinnedNotes.length > 0 && (
                  <div className="mb-6">
                    <h2 className="text-[10px] font-bold text-muted-foreground tracking-widest uppercase mb-4 px-2">
                      {t('notes.pinned')}
                    </h2>
                    <NotesEditorialView
                      notes={sortedPinnedNotes}
                      onOpen={(note: Note, readOnly?: boolean) => handleOpenNoteFresh(note.id, readOnly ?? false)}
                      notebookName={currentNotebook?.name}
                      onOpenHistory={handleOpenHistory}
                    />
                  </div>
                )}

                {sortedNotes.filter((note) => !note.isPinned).length > 0 && (
                  <NotesEditorialView
                    notes={sortedNotes.filter((note) => !note.isPinned)}
                    onOpen={(note, readOnly) => handleOpenNoteFresh(note.id, readOnly ?? false)}
                    notebookName={currentNotebook?.name}
                    onOpenHistory={handleOpenHistory}
                  />
                )}

                {notes.length === 0 && (
                  <div className="h-64 flex flex-col items-center justify-center text-center space-y-4">
                    <p className="font-memento-serif text-xl italic text-muted-foreground">
                      {t('notes.emptyState') || 'This notebook is waiting for its first vision.'}
                    </p>
                    <button
                      onClick={handleAddNote}
                      disabled={isCreating}
                      className="px-6 py-2 border border-foreground text-[13px] uppercase tracking-[0.2em] hover:bg-foreground hover:text-background transition-all"
                    >
                      {t('notes.createFirst') || 'Begin Drawing'}
                    </button>
                  </div>
                )}
              </div>
            )}
          </div>

          <footer className="px-12 py-6 border-t border-foreground/5 text-center mt-auto">
            <p className="text-[11px] text-muted-foreground uppercase tracking-[0.2em] font-medium">
              Memento &mdash; {new Date().getFullYear()}
            </p>
          </footer>
        </div>
      )}

      <MemoryEchoNotification onOpenNote={(noteId) => handleOpenNoteFresh(noteId)} />

      {notebookSuggestion && (
        <NotebookSuggestionToast
          noteId={notebookSuggestion.noteId}
          noteContent={notebookSuggestion.content}
          onDismiss={() => setNotebookSuggestion(null)}
        />
      )}

      {batchOrganizationOpen && (
        <BatchOrganizationDialog
          open={batchOrganizationOpen}
          onOpenChange={setBatchOrganizationOpen}
          onNotesMoved={() => router.refresh()}
        />
      )}

      {autoLabelOpen && (
        <AutoLabelSuggestionDialog
          open={autoLabelOpen}
          onOpenChange={(open) => {
            setAutoLabelOpen(open)
            if (!open) dismissLabelSuggestion()
          }}
          notebookId={suggestNotebookId}
          onLabelsCreated={() => router.refresh()}
        />
      )}

      <NoteHistoryModal
        open={historyOpen}
        onOpenChange={setHistoryOpen}
        note={historyNote}
        enabled={!!historyNote?.historyEnabled}
        onEnableHistory={async () => { if (historyNote) await handleEnableHistory(historyNote.id) }}
        onRestored={handleHistoryRestored}
      />
    </div>
  )
}
