/**
 * Platform context: recollections list and handlers for create/delete/rename/updateLastEdited/reorder/restore.
 * Used by AppSidebar, RecollectionsPage, and canvas route.
 */

import React, { createContext, useCallback, useContext, useMemo, useState } from 'react'
import type { Recollection } from './types'
import { saveGraphToStorage, RECOLLECTION_VERSION } from '@/app/recollections/recollectionGraphStorage'

const STORAGE_KEY = 'zui_platform_recollections'
const ORDER_STORAGE_KEY = 'zui_platform_recollection_order'
const RECENT_STORAGE_KEY = 'zui_platform_recent_recollection_ids'

const LEGACY_STORAGE_KEY = 'zui_platform_emanations'
const LEGACY_ORDER_STORAGE_KEY = 'zui_platform_emanation_order'
const LEGACY_RECENT_STORAGE_KEY = 'zui_platform_recent_emanation_ids'
const CANVAS_MINIMAP_KEY = 'zui_canvas_show_minimap'
const AI_CONNECTION_KEY = 'zui_ai_connection'
const RECENT_MAX = 5

export type AiConnectionProvider = 'openai' | 'local'

export type AiConnection = {
  provider: AiConnectionProvider
  baseURL: string
  model: string
  apiKey: string
}

const DEFAULT_AI_CONNECTION: AiConnection = {
  provider: 'local',
  baseURL: 'http://localhost:1234/v1',
  model: 'local-model',
  apiKey: '',
}

function loadAiConnection(): AiConnection {
  try {
    const raw = localStorage.getItem(AI_CONNECTION_KEY)
    if (!raw) return DEFAULT_AI_CONNECTION
    const parsed = JSON.parse(raw) as unknown
    if (!parsed || typeof parsed !== 'object') return DEFAULT_AI_CONNECTION
    const p = parsed as Record<string, unknown>
    return {
      provider: p.provider === 'openai' ? 'openai' : 'local',
      baseURL: typeof p.baseURL === 'string' ? p.baseURL : DEFAULT_AI_CONNECTION.baseURL,
      model: typeof p.model === 'string' ? p.model : DEFAULT_AI_CONNECTION.model,
      apiKey: typeof p.apiKey === 'string' ? p.apiKey : '',
    }
  } catch {
    return DEFAULT_AI_CONNECTION
  }
}

function saveAiConnection(value: AiConnection) {
  try {
    localStorage.setItem(AI_CONNECTION_KEY, JSON.stringify(value))
  } catch {}
}

function loadShowMinimap(): boolean {
  try {
    const raw = localStorage.getItem(CANVAS_MINIMAP_KEY)
    if (raw === 'true') return true
    if (raw === 'false') return false
  } catch {}
  return false
}

function saveShowMinimap(value: boolean) {
  try {
    localStorage.setItem(CANVAS_MINIMAP_KEY, JSON.stringify(value))
  } catch {}
}

function loadOrder(): string[] {
  try {
    let raw = localStorage.getItem(ORDER_STORAGE_KEY)
    if (!raw) {
      const legacy = localStorage.getItem(LEGACY_ORDER_STORAGE_KEY)
      if (legacy) {
        localStorage.setItem(ORDER_STORAGE_KEY, legacy)
        localStorage.removeItem(LEGACY_ORDER_STORAGE_KEY)
        raw = legacy
      } else return []
    }
    const parsed = JSON.parse(raw) as unknown
    return Array.isArray(parsed) ? parsed.filter((id): id is string => typeof id === 'string') : []
  } catch {
    return []
  }
}

function saveOrder(ids: string[]) {
  localStorage.setItem(ORDER_STORAGE_KEY, JSON.stringify(ids))
}

function loadRecentIds(): string[] {
  try {
    let raw = localStorage.getItem(RECENT_STORAGE_KEY)
    if (!raw) {
      const legacy = localStorage.getItem(LEGACY_RECENT_STORAGE_KEY)
      if (legacy) {
        localStorage.setItem(RECENT_STORAGE_KEY, legacy)
        localStorage.removeItem(LEGACY_RECENT_STORAGE_KEY)
        raw = legacy
      } else return []
    }
    const parsed = JSON.parse(raw) as unknown
    return Array.isArray(parsed) ? parsed.filter((id): id is string => typeof id === 'string').slice(0, RECENT_MAX) : []
  } catch {
    return []
  }
}

function saveRecentIds(ids: string[]) {
  localStorage.setItem(RECENT_STORAGE_KEY, JSON.stringify(ids))
}

function loadRecollections(): Recollection[] {
  try {
    let raw = localStorage.getItem(STORAGE_KEY)
    if (!raw) {
      const legacy = localStorage.getItem(LEGACY_STORAGE_KEY)
      if (legacy) {
        localStorage.setItem(STORAGE_KEY, legacy)
        localStorage.removeItem(LEGACY_STORAGE_KEY)
        raw = legacy
      } else return []
    }
    const parsed = JSON.parse(raw) as unknown
    if (!Array.isArray(parsed)) return []
    return parsed
      .filter(
        (p): p is Recollection =>
          p &&
          typeof p === 'object' &&
          typeof (p as Recollection).id === 'string' &&
          typeof (p as Recollection).name === 'string' &&
          typeof (p as Recollection).iconId === 'string' &&
          typeof (p as Recollection).createdAt === 'number'
      )
      .map((p) => ({
        ...p,
        lastEditedAt: typeof (p as Recollection).lastEditedAt === 'number' ? (p as Recollection).lastEditedAt : p.createdAt,
      }))
  } catch {
    return []
  }
}

function saveRecollections(recollections: Recollection[]) {
  localStorage.setItem(STORAGE_KEY, JSON.stringify(recollections))
}

export type GraphSnapshot = { nodes: unknown[]; edges: unknown[] }

/** Recollections sorted by recollectionOrder, then by lastEditedAt desc for any not in order */
export function sortRecollectionsByOrder(recollections: Recollection[], order: string[]): Recollection[] {
  const byId = new Map(recollections.map((p) => [p.id, p]))
  const ordered: Recollection[] = []
  const seen = new Set<string>()
  for (const id of order) {
    const p = byId.get(id)
    if (p) {
      ordered.push(p)
      seen.add(id)
    }
  }
  const rest = recollections
    .filter((p) => !seen.has(p.id))
    .sort((a, b) => (b.lastEditedAt ?? b.createdAt) - (a.lastEditedAt ?? a.createdAt))
  return [...ordered, ...rest]
}

export type KosmosContextValue = {
  recollections: Recollection[]
  recollectionOrder: string[]
  /** Recollections in display order (sidebar order, then lastEditedAt) */
  orderedRecollections: Recollection[]
  /** Last RECENT_MAX accessed recollection IDs (most recent first) */
  recentRecollectionIds: string[]
  recordRecollectionAccess: (id: string) => void
  persist: (next: Recollection[]) => void
  createRecollection: (recollection: Recollection) => void
  deleteRecollection: (id: string) => void
  renameRecollection: (id: string, name: string) => void
  updateLastEdited: (id: string) => void
  reorderRecollections: (orderedIds: string[]) => void
  restoreRecollection: (recollection: Recollection, graphSnapshot: GraphSnapshot | null) => void
  /** Canvas: show React Flow minimap (persisted) */
  showMinimap: boolean
  setShowMinimap: (value: boolean) => void
  /** Agent node: AI connection (persisted). Sent to backend when running agent. */
  aiConnection: AiConnection
  setAiConnection: (value: AiConnection) => void
}

const KosmosContext = createContext<KosmosContextValue | null>(null)

export function KosmosProvider({ children }: { children: React.ReactNode }) {
  const [recollections, setRecollections] = useState<Recollection[]>(loadRecollections)
  const [recollectionOrder, setRecollectionOrder] = useState<string[]>(loadOrder)
  const [recentRecollectionIds, setRecentRecollectionIds] = useState<string[]>(loadRecentIds)
  const [showMinimap, setShowMinimapState] = useState<boolean>(loadShowMinimap)
  const [aiConnection, setAiConnectionState] = useState<AiConnection>(loadAiConnection)

  const setShowMinimap = useCallback((value: boolean) => {
    setShowMinimapState(value)
    saveShowMinimap(value)
  }, [])

  const setAiConnection = useCallback((value: AiConnection) => {
    setAiConnectionState(value)
    saveAiConnection(value)
  }, [])

  const persist = useCallback((next: Recollection[]) => {
    setRecollections(next)
    saveRecollections(next)
  }, [])

  const createRecollection = useCallback(
    (recollection: Recollection) => {
      const withEdited = { ...recollection, lastEditedAt: recollection.createdAt }
      persist([...recollections, withEdited])
      setRecollectionOrder((prev) => {
        const next = prev.includes(recollection.id) ? prev : [recollection.id, ...prev]
        saveOrder(next)
        return next
      })
    },
    [recollections, persist]
  )

  const deleteRecollection = useCallback(
    (id: string) => {
      const next = recollections.filter((p) => p.id !== id)
      persist(next)
      setRecollectionOrder((prev) => {
        const nextOrder = prev.filter((oid) => oid !== id)
        saveOrder(nextOrder)
        return nextOrder
      })
      setRecentRecollectionIds((prev) => {
        const next = prev.filter((oid) => oid !== id)
        saveRecentIds(next)
        return next
      })
    },
    [recollections, persist]
  )

  const renameRecollection = useCallback(
    (id: string, name: string) => {
      const next = recollections.map((p) => (p.id === id ? { ...p, name } : p))
      persist(next)
    },
    [recollections, persist]
  )

  const updateLastEdited = useCallback(
    (id: string) => {
      const now = Date.now()
      const next = recollections.map((p) => (p.id === id ? { ...p, lastEditedAt: now } : p))
      persist(next)
    },
    [recollections, persist]
  )

  const reorderRecollections = useCallback((orderedIds: string[]) => {
    setRecollectionOrder(orderedIds)
    saveOrder(orderedIds)
  }, [])

  const recordRecollectionAccess = useCallback((id: string) => {
    setRecentRecollectionIds((prev) => {
      const next = [id, ...prev.filter((x) => x !== id)].slice(0, RECENT_MAX)
      saveRecentIds(next)
      return next
    })
  }, [])

  const restoreRecollection = useCallback(
    (recollection: Recollection, graphSnapshot: GraphSnapshot | null) => {
      persist([...recollections, recollection])
      setRecollectionOrder((prev) => {
        const next = prev.includes(recollection.id) ? prev : [recollection.id, ...prev]
        saveOrder(next)
        return next
      })
      if (graphSnapshot) {
        saveGraphToStorage(recollection.id, {
          version: RECOLLECTION_VERSION,
          nodes: graphSnapshot.nodes,
          edges: graphSnapshot.edges,
        })
      }
    },
    [recollections, persist]
  )

  const orderedRecollections = useMemo(
    () => sortRecollectionsByOrder(recollections, recollectionOrder),
    [recollections, recollectionOrder]
  )

  const value: KosmosContextValue = useMemo(
    () => ({
      recollections,
      recollectionOrder,
      orderedRecollections,
      recentRecollectionIds,
      recordRecollectionAccess,
      persist,
      createRecollection,
      deleteRecollection,
      renameRecollection,
      updateLastEdited,
      reorderRecollections,
      restoreRecollection,
      showMinimap,
      setShowMinimap,
      aiConnection,
      setAiConnection,
    }),
    [
      recollections,
      recollectionOrder,
      orderedRecollections,
      recentRecollectionIds,
      recordRecollectionAccess,
      persist,
      createRecollection,
      deleteRecollection,
      renameRecollection,
      updateLastEdited,
      reorderRecollections,
      restoreRecollection,
      showMinimap,
      setShowMinimap,
      aiConnection,
      setAiConnection,
    ]
  )

  return <KosmosContext.Provider value={value}>{children}</KosmosContext.Provider>
}

export function usePlatform() {
  const ctx = useContext(KosmosContext)
  if (!ctx) throw new Error('usePlatform must be used within PlatformProvider')
  return ctx
}
