'use client'

import { createContext, useContext, useState, useEffect, useMemo, useCallback } from 'react'
import type { Notebook, Label, Note } from '@/lib/types'
import { useNoteRefresh } from './NoteRefreshContext'
import { toast } from 'sonner'

// ===== INPUT TYPES =====
export interface CreateNotebookInput {
  name: string
  icon?: string
  color?: string
}

export interface UpdateNotebookInput {
  name?: string
  icon?: string
  color?: string
}

export interface CreateLabelInput {
  name: string
  color?: string
  notebookId: string
}

export interface UpdateLabelInput {
  name?: string
  color?: string
}

// ===== CONTEXT VALUE =====
export interface NotebooksContextValue {
  // État global
  notebooks: Notebook[]
  currentNotebook: Notebook | null // null = "Notes générales"
  currentLabels: Label[] // Labels du notebook actuel
  isLoading: boolean
  isMovingNote: boolean
  error: string | null

  // Actions: Notebooks
  createNotebookOptimistic: (data: CreateNotebookInput) => Promise<void>
  updateNotebook: (notebookId: string, data: UpdateNotebookInput) => Promise<void>
  deleteNotebook: (notebookId: string) => Promise<void>
  updateNotebookOrderOptimistic: (notebookIds: string[]) => Promise<void>
  setCurrentNotebook: (notebook: Notebook | null) => void

  // Actions: Labels
  createLabel: (data: CreateLabelInput) => Promise<Label>
  updateLabel: (labelId: string, data: UpdateLabelInput) => Promise<void>
  deleteLabel: (labelId: string) => Promise<void>

  // Actions: Notes
  moveNoteToNotebookOptimistic: (noteId: string, notebookId: string | null) => Promise<void>

  /** Recharger la liste des carnets (ex. après maintenance étiquettes) */
  refreshNotebooks: () => Promise<void>

  // Actions: AI (stubs pour l'instant)
  suggestNotebookForNote: (noteContent: string) => Promise<Notebook | null>
  suggestLabelsForNote: (noteContent: string, notebookId: string) => Promise<string[]>
}

export const NotebooksContext = createContext<NotebooksContextValue | null>(null)

export function useNotebooks() {
  const context = useContext(NotebooksContext)
  if (!context) {
    throw new Error('useNotebooks must be used within NotebooksProvider')
  }
  return context
}

interface NotebooksProviderProps {
  children: React.ReactNode
  initialNotebooks?: Notebook[]
}

export function NotebooksProvider({ children, initialNotebooks = [] }: NotebooksProviderProps) {
  // ===== BASE STATE =====
  const [notebooks, setNotebooks] = useState<Notebook[]>(initialNotebooks)
  const [currentNotebook, setCurrentNotebook] = useState<Notebook | null>(null)
  const [isLoading, setIsLoading] = useState(true)
  const [isMovingNote, setIsMovingNote] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const { triggerRefresh } = useNoteRefresh() // Get triggerRefresh from context

  // ===== DERIVED STATE =====
  const currentLabels = useMemo(() => {
    if (!currentNotebook) return []
    return notebooks.find(nb => nb.id === currentNotebook.id)?.labels ?? []
  }, [currentNotebook, notebooks])

  // ===== DATA LOADING =====
  const loadNotebooks = useCallback(async () => {
    setIsLoading(true)
    setError(null)

    try {
      const response = await fetch('/api/notebooks')
      if (!response.ok) throw new Error('Failed to load notebooks')

      const data = await response.json()
      setNotebooks(data.notebooks || [])
    } catch (err) {
      console.error('Failed to load notebooks:', err)
      setError(err instanceof Error ? err.message : 'Unknown error')
    } finally {
      setIsLoading(false)
    }
  }, [])

  useEffect(() => {
    loadNotebooks()
  }, [loadNotebooks])

  // ===== ACTIONS: NOTEBOOKS =====
  const createNotebookOptimistic = useCallback(async (data: CreateNotebookInput) => {
    const response = await fetch('/api/notebooks', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data),
    })

    if (!response.ok) {
      throw new Error('Failed to create notebook')
    }

    // Reload notebooks from server to update sidebar state
    await loadNotebooks()
    triggerRefresh()
  }, [loadNotebooks, triggerRefresh])

  const updateNotebook = useCallback(async (notebookId: string, data: UpdateNotebookInput) => {
    const response = await fetch(`/api/notebooks/${notebookId}`, {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data),
    })

    if (!response.ok) {
      throw new Error('Failed to update notebook')
    }

    await loadNotebooks()
    triggerRefresh()
  }, [loadNotebooks, triggerRefresh])

  const deleteNotebook = useCallback(async (notebookId: string) => {
    const response = await fetch(`/api/notebooks/${notebookId}`, {
      method: 'DELETE',
    })

    if (!response.ok) {
      throw new Error('Failed to delete notebook')
    }

    await loadNotebooks()
    triggerRefresh()
  }, [loadNotebooks, triggerRefresh])

  const updateNotebookOrderOptimistic = useCallback(async (notebookIds: string[]) => {
    const response = await fetch('/api/notebooks/reorder', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ notebookIds }),
    })

    if (!response.ok) {
      throw new Error('Failed to update notebook order')
    }

    await loadNotebooks()
    triggerRefresh()
  }, [loadNotebooks, triggerRefresh])

  // ===== ACTIONS: LABELS =====
  const createLabel = useCallback(async (data: CreateLabelInput) => {
    const response = await fetch('/api/labels', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data),
    })

    if (!response.ok) {
      throw new Error('Failed to create label')
    }

    const result = await response.json()
    return result
  }, [])

  const updateLabel = useCallback(async (labelId: string, data: UpdateLabelInput) => {
    const response = await fetch(`/api/labels/${labelId}`, {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data),
    })

    if (!response.ok) {
      throw new Error('Failed to update label')
    }
  }, [])

  const deleteLabel = useCallback(async (labelId: string) => {
    const response = await fetch(`/api/labels/${labelId}`, {
      method: 'DELETE',
    })

    if (!response.ok) {
      throw new Error('Failed to delete label')
    }
  }, [])

  // ===== ACTIONS: NOTES =====
  const moveNoteToNotebookOptimistic = useCallback(async (noteId: string, notebookId: string | null) => {
    setIsMovingNote(true)
    try {
      const response = await fetch(`/api/notes/${noteId}/move`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ notebookId }),
      })

      if (!response.ok) {
        throw new Error('Failed to move note')
      }

      await loadNotebooks()
      triggerRefresh()
    } catch (error) {
      toast.error('Failed to move note. Please try again.')
      throw error
    } finally {
      setIsMovingNote(false)
    }
  }, [loadNotebooks, triggerRefresh])

  // ===== ACTIONS: AI (STUBS) =====
  const suggestNotebookForNote = useCallback(async (_noteContent: string) => {
    // Stub pour l'instant - retourne null
    return null
  }, [])

  const suggestLabelsForNote = useCallback(async (_noteContent: string, _notebookId: string) => {
    // Stub pour l'instant - retourne tableau vide
    return []
  }, [])

  // ===== CONTEXT VALUE =====
  const value: NotebooksContextValue = useMemo(() => ({
    notebooks,
    currentNotebook,
    currentLabels,
    isLoading,
    isMovingNote,
    error,
    createNotebookOptimistic,
    updateNotebook,
    deleteNotebook,
    updateNotebookOrderOptimistic,
    setCurrentNotebook,
    createLabel,
    updateLabel,
    deleteLabel,
    moveNoteToNotebookOptimistic,
    refreshNotebooks: loadNotebooks,
    suggestNotebookForNote,
    suggestLabelsForNote,
  }), [
    notebooks,
    currentNotebook,
    currentLabels,
    isLoading,
    isMovingNote,
    error,
    createNotebookOptimistic,
    updateNotebook,
    deleteNotebook,
    updateNotebookOrderOptimistic,
    createLabel,
    updateLabel,
    deleteLabel,
    moveNoteToNotebookOptimistic,
    loadNotebooks,
    suggestNotebookForNote,
    suggestLabelsForNote,
  ])

  return (
    <NotebooksContext.Provider value={value}>
      {children}
    </NotebooksContext.Provider>
  )
}
