import React, { useEffect, useRef, useState } from 'react'

const TOAST_DURATION_MS = {
  info: 3600,
  success: 4800,
  warning: 5600
}

function fileSyncMeta(file) {
  const sync = file?.sync || {}
  const status = String(sync.status || 'pending')
  const progress = Math.max(0, Math.min(100, Number(sync.progress) || 0))
  const detail = String(sync.detail || '').trim()
  const error = String(sync.error || '').trim()
  const enrichEnabled = !!file?.enrich_enabled

  if (status === 'ready') {
    return {
      status,
      progress: 100,
      label: 'Available',
      detail: detail || (enrichEnabled ? 'Ready in chat with enrichment enabled.' : 'Ready in chat with raw indexing only.')
    }
  }

  if (status === 'failed') {
    return {
      status,
      progress: 100,
      label: 'Sync failed',
      detail: error || detail || 'Heimgeist could not finish syncing this file.'
    }
  }

  if (status === 'syncing') {
    return {
      status,
      progress,
      label: progress > 0 ? `Syncing ${Math.round(progress)}%` : 'Syncing',
      detail: detail || 'Rebuilding the corpus and indexes. Selected files may also be enriched.'
    }
  }

  return {
    status: 'pending',
    progress: 6,
    label: 'Queued',
    detail: 'Waiting to rebuild the retrieval pipeline.'
  }
}

export default function LibraryManager({
  apiBase,
  library,
  jobs,
  onRefresh,
  onDeleted
}) {
  const [busy, setBusy] = useState(false)
  const [confirmDelete, setConfirmDelete] = useState(false)
  const [errorMessage, setErrorMessage] = useState('')
  const [toasts, setToasts] = useState([])
  const toastTimeoutsRef = useRef(new Map())
  const toastIdRef = useRef(0)
  const previousLibraryStateRef = useRef(null)

  useEffect(() => {
    setConfirmDelete(false)
    setErrorMessage('')
  }, [library?.slug, library?.name])

  function dismissToast(id) {
    const timeoutId = toastTimeoutsRef.current.get(id)
    if (timeoutId) {
      clearTimeout(timeoutId)
      toastTimeoutsRef.current.delete(id)
    }
    setToasts(current => current.filter(toast => toast.id !== id))
  }

  function clearToasts() {
    toastTimeoutsRef.current.forEach(timeoutId => clearTimeout(timeoutId))
    toastTimeoutsRef.current.clear()
    setToasts([])
  }

  function queueToast(message, tone = 'info') {
    setToasts(current => {
      if (current.some(toast => toast.message === message && toast.tone === tone)) {
        return current
      }

      const id = `library-toast-${toastIdRef.current++}`
      const next = [...current, { id, message, tone }].slice(-3)
      const timeoutId = window.setTimeout(() => dismissToast(id), TOAST_DURATION_MS[tone] || TOAST_DURATION_MS.info)
      toastTimeoutsRef.current.set(id, timeoutId)
      return next
    })
  }

  useEffect(() => () => {
    toastTimeoutsRef.current.forEach(timeoutId => clearTimeout(timeoutId))
    toastTimeoutsRef.current.clear()
  }, [])

  async function expectOk(response) {
    if (response.ok) return response
    const detail = await response.text()
    throw new Error(detail || `HTTP ${response.status}`)
  }

  async function runAction(fn) {
    setBusy(true)
    try {
      setErrorMessage('')
      await fn()
      setConfirmDelete(false)
    } finally {
      setBusy(false)
      await onRefresh()
    }
  }

  async function addPaths() {
    if (!library) return
    const paths = await window.electronAPI?.pickPaths?.()
    if (!Array.isArray(paths) || paths.length === 0) return
    try {
      await runAction(async () => {
        const response = await fetch(`${apiBase}/libraries/${library.slug}/files/register`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ paths })
        })
        await expectOk(response)
      })
    } catch (error) {
      setErrorMessage(String(error?.message || error))
    }
  }

  async function removeFile(rel) {
    if (!library) return
    try {
      await runAction(async () => {
        const response = await fetch(`${apiBase}/libraries/${library.slug}/files`, {
          method: 'DELETE',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ rel })
        })
        await expectOk(response)
      })
    } catch (error) {
      setErrorMessage(String(error?.message || error))
    }
  }

  async function updateFileEnrichment(rel, enabled) {
    if (!library) return
    try {
      await runAction(async () => {
        const response = await fetch(`${apiBase}/libraries/${library.slug}/files/enrichment`, {
          method: 'PATCH',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ rel, enabled })
        })
        await expectOk(response)
      })
    } catch (error) {
      setErrorMessage(String(error?.message || error))
    }
  }

  async function deleteLibrary() {
    if (!library) return
    await runAction(async () => {
      const response = await fetch(`${apiBase}/libraries/${library.slug}`, { method: 'DELETE' })
      await expectOk(response)
    })
    onDeleted?.(library.slug)
  }

  async function retrySync() {
    if (!library) return
    try {
      await runAction(async () => {
        const response = await fetch(`${apiBase}/libraries/${library.slug}/jobs/prepare`, {
          method: 'POST'
        })
        await expectOk(response)
      })
    } catch (error) {
      setErrorMessage(String(error?.message || error))
    }
  }

  if (!library) {
    return (
      <div className="placeholder-view">
        <p>Create a database and add files. Heimgeist will raw-index them automatically, and you can opt specific files into enrichment.</p>
      </div>
    )
  }

  const activeJobs = (jobs || []).filter(job => job.slug === library.slug && (job.status === 'queued' || job.status === 'running'))
  const isSyncing = activeJobs.length > 0
  const isReadyForChat = !!library.states?.is_indexed
  const hasFailedFiles = (library.files || []).some(file => file?.sync?.status === 'failed')

  useEffect(() => {
    if (!library?.slug) {
      previousLibraryStateRef.current = null
      clearToasts()
      return
    }

    const nextState = {
      slug: library.slug,
      hasFiles: !!library.files?.length,
      isSyncing,
      isReadyForChat,
      hasFailedFiles
    }

    const previousState = previousLibraryStateRef.current
    if (!previousState || previousState.slug !== nextState.slug) {
      previousLibraryStateRef.current = nextState
      clearToasts()
      return
    }

    if (!previousState.isSyncing && nextState.isSyncing) {
      queueToast(
        'Syncing this database. Heimgeist is rebuilding the corpus and indexes automatically, and only selected files will run through enrichment.'
      )
    }

    if (previousState.isSyncing && !nextState.isSyncing) {
      if (nextState.hasFailedFiles) {
        queueToast(
          'Some files did not finish syncing. Their tiles show the failure state and error details.',
          'warning'
        )
      } else if (nextState.isReadyForChat) {
        queueToast(
          'Sync complete. This database is ready in chat. Raw indexing stays on by default; enable enrichment only for files that need deeper recall.',
          'success'
        )
      } else if (!nextState.hasFiles) {
        queueToast('Add files to make this database available in chat.')
      }
    } else if (previousState.hasFiles && !nextState.hasFiles && !nextState.isSyncing) {
      queueToast('All files were removed. Add files to make this database available in chat.')
    } else if (!previousState.hasFailedFiles && nextState.hasFailedFiles && !nextState.isSyncing) {
      queueToast(
        'Some files did not finish syncing. Their tiles show the failure state and error details.',
        'warning'
      )
    }

    previousLibraryStateRef.current = nextState
  }, [
    library?.slug,
    library?.files?.length,
    hasFailedFiles,
    isReadyForChat,
    isSyncing
  ])

  return (
    <div className="library-panel">
      <div className="library-panel-scroll">
        {confirmDelete && (
          <div className="library-inline-form danger-zone">
            <div className="muted-copy">Delete "{library.name}"? This removes the registered files and local retrieval data for this database.</div>
            <div className="new-db-actions">
              <button
                className="button danger"
                disabled={busy}
                onClick={() => deleteLibrary().catch((error) => setErrorMessage(String(error?.message || error)))}
              >
                Confirm Delete
              </button>
              <button className="button ghost" onClick={() => setConfirmDelete(false)}>Cancel</button>
            </div>
          </div>
        )}

        {errorMessage && <div className="form-error">{errorMessage}</div>}

        <div className="library-toolbar">
          <button className="button" disabled={busy} onClick={addPaths}>Add Files</button>
          {library.files?.length > 0 && !isSyncing && !isReadyForChat && (
            <button className="button ghost" disabled={busy} onClick={retrySync}>Retry Sync</button>
          )}
          <button
            className="button danger"
            onClick={() => {
              setConfirmDelete(true)
              setErrorMessage('')
            }}
          >
            Delete
          </button>
        </div>

        <div className="library-states">
          <div className={`state-pill ${library.states?.has_files ? 'ready' : ''}`}>Files: {library.files?.length || 0}</div>
          <div className={`state-pill ${(library.states?.enrichment_enabled_files || 0) > 0 ? 'ready' : ''}`}>
            Enrich: {library.states?.enrichment_enabled_files || 0}
          </div>
          <div className={`state-pill ${isReadyForChat ? 'ready' : ''}`}>
            {isSyncing ? 'Syncing' : isReadyForChat ? 'Ready' : library.files?.length ? 'Needs sync' : 'No data yet'}
          </div>
        </div>

        <div className="library-files">
          <h2>Files</h2>
          {library.files?.length ? (
            <div className="library-file-list">
              {library.files.map(file => {
                const sync = fileSyncMeta(file)
                return (
                  <div key={file.sha256 || file.rel} className="library-file-row">
                    <div className="library-file-meta">
                      <div className="library-file-name">{file.name || file.path}</div>
                      <div className="library-file-path">{file.path}</div>
                      <div className={`library-file-mode ${file.enrich_enabled ? 'enabled' : ''}`}>
                        {file.enrich_enabled ? 'Enrichment on' : 'Raw only'}
                      </div>
                      <div className="library-file-sync">
                        <div className="library-file-sync-row">
                          <span className={`library-file-sync-label ${sync.status}`}>{sync.label}</span>
                          <span className="library-file-sync-detail">{sync.detail}</span>
                        </div>
                        <div
                          className={`library-file-progress ${sync.status}`}
                          role="progressbar"
                          aria-valuemin="0"
                          aria-valuemax="100"
                          aria-valuenow={Math.round(sync.progress)}
                          aria-label={`${file.name || file.path} sync progress`}
                        >
                          <div
                            className="library-file-progress-bar"
                            style={{ width: `${sync.progress}%` }}
                          />
                        </div>
                      </div>
                    </div>
                    <div className="library-file-actions">
                      <button
                        className="button ghost"
                        disabled={busy || isSyncing}
                        onClick={() => updateFileEnrichment(file.rel, !file.enrich_enabled)}
                      >
                        {file.enrich_enabled ? 'Use Raw Only' : 'Enable Enrich'}
                      </button>
                      <button className="button ghost" onClick={() => window.electronAPI?.openPath?.(file.path)}>Open</button>
                      <button className="button ghost" disabled={busy || isSyncing} onClick={() => removeFile(file.rel)}>Remove</button>
                    </div>
                  </div>
                )
              })}
            </div>
          ) : (
            <p className="muted-copy">No files registered yet.</p>
          )}
        </div>
      </div>

      {toasts.length > 0 && (
        <div className="library-toast-stack" aria-live="polite">
          {toasts.map(toast => (
            <div
              key={toast.id}
              className={`library-toast ${toast.tone}`}
              role={toast.tone === 'warning' ? 'alert' : 'status'}
            >
              {toast.message}
            </div>
          ))}
        </div>
      )}
    </div>
  )
}
