import { useState, useCallback, useRef } from 'react'

const STORAGE_KEY = 'calctext-documents'
const FOLDERS_KEY = 'calctext-folders'
const TABS_KEY = 'calctext-tabs'
const ACTIVE_KEY = 'calctext-active-tab'
const SIDEBAR_KEY = 'calctext-sidebar'

export interface CalcDocument {
  id: string
  title: string
  content: string
  folderId: string | null
  isFavorite: boolean
  createdAt: string
  updatedAt: string
}

export interface CalcFolder {
  id: string
  name: string
  parentId: string | null
  order: number
}

interface StoreState {
  documents: CalcDocument[]
  folders: CalcFolder[]
  openTabIds: string[]
  activeTabId: string
}

const WELCOME_DOC: CalcDocument = {
  id: 'welcome',
  title: 'Welcome',
  content: `# CalcText

// Basic arithmetic
2 + 3
10 * 4.5
100 / 7

// Variables
price = 49.99
quantity = 3
subtotal = price * quantity

// Percentages
tax = subtotal * 8%
total = subtotal + tax

// Functions
sqrt(144)
2 ^ 10
`,
  folderId: null,
  isFavorite: false,
  createdAt: new Date().toISOString(),
  updatedAt: new Date().toISOString(),
}

function generateId(): string {
  return Date.now().toString(36) + Math.random().toString(36).slice(2, 8)
}

function loadState(): StoreState {
  try {
    const docsJson = localStorage.getItem(STORAGE_KEY)
    const foldersJson = localStorage.getItem(FOLDERS_KEY)
    const tabsJson = localStorage.getItem(TABS_KEY)
    const activeId = localStorage.getItem(ACTIVE_KEY)

    const documents: CalcDocument[] = docsJson ? JSON.parse(docsJson) : [WELCOME_DOC]
    const folders: CalcFolder[] = foldersJson ? JSON.parse(foldersJson) : []
    const openTabIds: string[] = tabsJson ? JSON.parse(tabsJson) : [documents[0]?.id ?? 'welcome']
    const activeTabId = activeId && openTabIds.includes(activeId) ? activeId : openTabIds[0] ?? ''

    if (documents.length === 0) documents.push(WELCOME_DOC)
    if (openTabIds.length === 0) openTabIds.push(documents[0].id)

    return { documents, folders, openTabIds, activeTabId }
  } catch {
    return { documents: [WELCOME_DOC], folders: [], openTabIds: ['welcome'], activeTabId: 'welcome' }
  }
}

function saveState(state: StoreState) {
  try {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(state.documents))
    localStorage.setItem(FOLDERS_KEY, JSON.stringify(state.folders))
    localStorage.setItem(TABS_KEY, JSON.stringify(state.openTabIds))
    localStorage.setItem(ACTIVE_KEY, state.activeTabId)
  } catch { /* */ }
}

export function loadSidebarState(): { visible: boolean; width: number } {
  try {
    const json = localStorage.getItem(SIDEBAR_KEY)
    if (json) return JSON.parse(json)
  } catch { /* */ }
  return { visible: true, width: 240 }
}

export function saveSidebarState(s: { visible: boolean; width: number }) {
  try { localStorage.setItem(SIDEBAR_KEY, JSON.stringify(s)) } catch { /* */ }
}

export function useDocumentStore() {
  const [state, setState] = useState<StoreState>(loadState)
  const saveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
  // Use a ref to always have latest state for return values
  const stateRef = useRef(state)
  stateRef.current = state

  const persist = useCallback((next: StoreState) => {
    setState(next)
    saveState(next)
  }, [])

  const persistDebounced = useCallback((next: StoreState) => {
    setState(next)
    if (saveTimerRef.current) clearTimeout(saveTimerRef.current)
    saveTimerRef.current = setTimeout(() => saveState(next), 300)
  }, [])

  // Use functional updates to avoid stale closures

  const setActiveTab = useCallback((id: string) => {
    setState(prev => {
      const next = { ...prev, activeTabId: id }
      saveState(next)
      return next
    })
  }, [])

  const createDocument = useCallback((title?: string, content?: string): CalcDocument => {
    const id = generateId()
    const now = new Date().toISOString()
    // Read current state to count untitled
    const cur = stateRef.current
    const existingUntitled = cur.documents.filter(d => d.title.startsWith('Untitled')).length
    const newDoc: CalcDocument = {
      id,
      title: title ?? (existingUntitled === 0 ? 'Untitled' : `Untitled ${existingUntitled + 1}`),
      content: content ?? '',
      folderId: null,
      isFavorite: false,
      createdAt: now,
      updatedAt: now,
    }
    setState(prev => {
      const next: StoreState = {
        ...prev,
        documents: [...prev.documents, newDoc],
        openTabIds: [...prev.openTabIds, id],
        activeTabId: id,
      }
      saveState(next)
      return next
    })
    return newDoc
  }, [])

  const updateContent = useCallback((id: string, content: string) => {
    setState(prev => {
      const next: StoreState = {
        ...prev,
        documents: prev.documents.map(d =>
          d.id === id ? { ...d, content, updatedAt: new Date().toISOString() } : d
        ),
      }
      // debounced save
      if (saveTimerRef.current) clearTimeout(saveTimerRef.current)
      saveTimerRef.current = setTimeout(() => saveState(next), 300)
      return next
    })
  }, [])

  const renameDocument = useCallback((id: string, title: string) => {
    setState(prev => {
      const next: StoreState = {
        ...prev,
        documents: prev.documents.map(d =>
          d.id === id ? { ...d, title: title.trim() || 'Untitled', updatedAt: new Date().toISOString() } : d
        ),
      }
      saveState(next)
      return next
    })
  }, [])

  const closeTab = useCallback((id: string) => {
    setState(prev => {
      let nextTabs = prev.openTabIds.filter(tid => tid !== id)
      let nextActive = prev.activeTabId

      if (nextTabs.length === 0) {
        const newId = generateId()
        const newDoc: CalcDocument = {
          id: newId, title: 'Untitled', content: '',
          folderId: null, isFavorite: false,
          createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(),
        }
        const next: StoreState = {
          ...prev,
          documents: [...prev.documents, newDoc],
          openTabIds: [newId],
          activeTabId: newId,
        }
        saveState(next)
        return next
      }

      if (nextActive === id) {
        const closedIdx = prev.openTabIds.indexOf(id)
        nextActive = nextTabs[Math.min(closedIdx, nextTabs.length - 1)]
      }

      const next = { ...prev, openTabIds: nextTabs, activeTabId: nextActive }
      saveState(next)
      return next
    })
  }, [])

  const deleteDocument = useCallback((id: string) => {
    setState(prev => {
      const nextDocs = prev.documents.filter(d => d.id !== id)
      let nextTabs = prev.openTabIds.filter(tid => tid !== id)
      let nextActive = prev.activeTabId

      if (nextDocs.length === 0) {
        const wd = { ...WELCOME_DOC, id: generateId() }
        nextDocs.push(wd)
      }
      if (nextTabs.length === 0) nextTabs = [nextDocs[0].id]
      if (!nextTabs.includes(nextActive)) nextActive = nextTabs[0]

      const next: StoreState = { ...prev, documents: nextDocs, openTabIds: nextTabs, activeTabId: nextActive }
      saveState(next)
      return next
    })
  }, [])

  const reorderTabs = useCallback((fromIndex: number, toIndex: number) => {
    setState(prev => {
      const tabs = [...prev.openTabIds]
      const [moved] = tabs.splice(fromIndex, 1)
      tabs.splice(toIndex, 0, moved)
      const next = { ...prev, openTabIds: tabs }
      saveState(next)
      return next
    })
  }, [])

  const openDocument = useCallback((id: string) => {
    setState(prev => {
      const next = prev.openTabIds.includes(id)
        ? { ...prev, activeTabId: id }
        : { ...prev, openTabIds: [...prev.openTabIds, id], activeTabId: id }
      saveState(next)
      return next
    })
  }, [])

  const toggleFavorite = useCallback((id: string) => {
    setState(prev => {
      const next: StoreState = {
        ...prev,
        documents: prev.documents.map(d =>
          d.id === id ? { ...d, isFavorite: !d.isFavorite } : d
        ),
      }
      saveState(next)
      return next
    })
  }, [])

  const moveToFolder = useCallback((docId: string, folderId: string | null) => {
    setState(prev => {
      const next: StoreState = {
        ...prev,
        documents: prev.documents.map(d =>
          d.id === docId ? { ...d, folderId } : d
        ),
      }
      saveState(next)
      return next
    })
  }, [])

  const createFolder = useCallback((name?: string, parentId?: string | null): CalcFolder => {
    const folder: CalcFolder = {
      id: generateId(),
      name: name ?? 'New Folder',
      parentId: parentId ?? null,
      order: stateRef.current.folders.length,
    }
    setState(prev => {
      const next = { ...prev, folders: [...prev.folders, folder] }
      saveState(next)
      return next
    })
    return folder
  }, [])

  const renameFolder = useCallback((id: string, name: string) => {
    setState(prev => {
      const next: StoreState = {
        ...prev,
        folders: prev.folders.map(f =>
          f.id === id ? { ...f, name: name.trim() || 'Folder' } : f
        ),
      }
      saveState(next)
      return next
    })
  }, [])

  const deleteFolder = useCallback((id: string) => {
    setState(prev => {
      const next: StoreState = {
        ...prev,
        documents: prev.documents.map(d => d.folderId === id ? { ...d, folderId: null } : d),
        folders: prev.folders.filter(f => f.id !== id && f.parentId !== id),
      }
      saveState(next)
      return next
    })
  }, [])

  const activeDoc = state.documents.find(d => d.id === state.activeTabId) ?? state.documents[0]
  const openDocs = state.openTabIds
    .map(id => state.documents.find(d => d.id === id))
    .filter((d): d is CalcDocument => d != null)

  return {
    documents: state.documents,
    folders: state.folders,
    openDocs,
    openTabIds: state.openTabIds,
    activeTabId: state.activeTabId,
    activeDoc,
    setActiveTab,
    createDocument,
    updateContent,
    renameDocument,
    closeTab,
    deleteDocument,
    reorderTabs,
    openDocument,
    toggleFavorite,
    moveToFolder,
    createFolder,
    renameFolder,
    deleteFolder,
  }
}
