import { useState, useEffect, useCallback, useMemo, useRef, lazy, Suspense } from 'react'
import { ServerCrash, SearchX, Plus, RefreshCw } from 'lucide-react'
import { fetchAllStatus, containerAction, addVps, deleteVps, fetchLogs, authStatus, getToken, setToken, composeUpdate, updateVps, updateAgent, exportVps } from './api/client'
import Header           from './components/Header'
import VpsCard          from './components/VpsCard'
import LogsModal        from './components/LogsModal'
import AddVpsModal      from './components/AddVpsModal'
import EditVpsModal     from './components/EditVpsModal'
import StatsModal       from './components/StatsModal'
import LoginPage        from './components/LoginPage'
import ProfilePage      from './components/ProfilePage'
import AdminPage        from './components/AdminPage'
import DashboardToolbar from './components/DashboardToolbar'
import ConfirmDialog    from './components/ui/ConfirmDialog'
import { useToast }     from './components/ui/Toast'
import { Button, EmptyState, Skeleton } from './components/ui/controls'
import { copyText, downloadText } from './lib/clipboard'

// xterm.js pèse ~300 kB : chargé seulement à l'ouverture d'un terminal.
const TerminalModal = lazy(() => import('./components/TerminalModal'))

const INTERVAL_OPTIONS = [
  { label: '10 s',  value: 10_000 },
  { label: '30 s',  value: 30_000 },
  { label: '1 min', value: 60_000 },
  { label: '2 min', value: 120_000 },
  { label: '5 min', value: 300_000 },
  { label: 'Off',   value: 0 },
]

const ACTION_LABELS = {
  start:   'démarré',
  stop:    'arrêté',
  restart: 'redémarré',
}

/** Un VPS « à problème » : injoignable, conteneur non démarré ou en mauvaise santé. */
function hasIssue(vps) {
  if (!vps.online) return true
  if (vps.containers.some(c => c.status !== 'running' || c.health === 'unhealthy')) return true
  return (vps.services ?? []).some(s => s.active === 'failed')
}

/** Champs pris en compte par la recherche libre. */
function vpsMatchesQuery(vps, query) {
  const haystack = [
    vps.name,
    vps.host,
    vps.description,
    ...(vps.tags ?? []),
    ...vps.containers.flatMap(c => [c.name, c.image, c.compose_project]),
    ...(vps.services ?? []).map(s => s.name),
  ]
  return haystack.filter(Boolean).some(value => value.toLowerCase().includes(query))
}

export default function App() {
  const toast = useToast()

  const [token,       setTokenState]  = useState(() => getToken())
  const [username,    setUsername]    = useState(null)
  const [role,        setRole]        = useState(null)
  const [page,        setPage]        = useState('main') // 'main' | 'profile' | 'admin'
  const [isFirstUser, setIsFirstUser] = useState(false)
  const [passkeyEnabled, setPasskeyEnabled] = useState(false)
  const [terminalEnabled, setTerminalEnabled] = useState(true)
  const [authChecked, setAuthChecked] = useState(false)

  const [vpsList,     setVpsList]     = useState([])
  const [loading,     setLoading]     = useState(true)
  const [refreshing,  setRefreshing]  = useState(false)
  const [error,       setError]       = useState(null)
  const [lastUpdate,  setLastUpdate]  = useState(null)
  const [logsModal,   setLogsModal]   = useState(null)
  const [logsContent, setLogsContent] = useState('')
  const [logsLoading, setLogsLoading] = useState(false)
  const [showAddVps,  setShowAddVps]  = useState(false)
  const [editVps,     setEditVps]     = useState(null)   // objet vps à éditer
  const [deleteTarget, setDeleteTarget] = useState(null) // vps en attente de confirmation
  const [deleting,     setDeleting]     = useState(false)

  const [refreshInterval, setRefreshInterval] = useState(() => {
    const stored = localStorage.getItem('refreshInterval')
    return stored ? parseInt(stored, 10) : 30_000
  })

  // ─── Filtres du tableau de bord ─────────────────────────────────────────
  const [search,     setSearch]     = useState('')
  const [status,     setStatus]     = useState(() => localStorage.getItem('filterStatus') ?? 'all')
  const [activeTags, setActiveTags] = useState(() => {
    try { return JSON.parse(localStorage.getItem('filterTags') ?? '[]') } catch { return [] }
  })
  const [sort, setSort] = useState(() => localStorage.getItem('sortBy') ?? 'name')
  const searchRef = useRef(null)

  const handleIntervalChange = (val) => {
    setRefreshInterval(val)
    localStorage.setItem('refreshInterval', val)
  }

  const handleStatusChange = (val) => {
    setStatus(val)
    localStorage.setItem('filterStatus', val)
  }

  const handleSortChange = (val) => {
    setSort(val)
    localStorage.setItem('sortBy', val)
  }

  const handleToggleTag = (tag) => {
    setActiveTags(prev => {
      const next = prev.includes(tag) ? prev.filter(t => t !== tag) : [...prev, tag]
      localStorage.setItem('filterTags', JSON.stringify(next))
      return next
    })
  }

  const [updateModal,   setUpdateModal]   = useState(null)   // { vpsId, project }
  const [updateContent, setUpdateContent] = useState('')
  const [updateLoading, setUpdateLoading] = useState(false)

  const [statsModal,    setStatsModal]    = useState(null)   // { vpsId, vpsName }
  const [terminalModal, setTerminalModal] = useState(null)   // { vps, container }

  // Vérifie si des utilisateurs existent (pour afficher login ou register)
  useEffect(() => {
    authStatus()
      .then(({ has_users, passkey_enabled, terminal_enabled }) => {
        setIsFirstUser(!has_users)
        setPasskeyEnabled(!!passkey_enabled)
        setTerminalEnabled(terminal_enabled !== false)
      })
      .catch(() => setIsFirstUser(false))
      .finally(() => setAuthChecked(true))
  }, [])

  // Écoute l'événement d'expiration de token émis par client.js
  useEffect(() => {
    const onExpired = () => {
      setToken(null)
      setTokenState(null)
      setUsername(null)
      setRole(null)
      setPage('main')
    }
    window.addEventListener('auth:expired', onExpired)
    return () => window.removeEventListener('auth:expired', onExpired)
  }, [])

  const handleAuthenticated = (accessToken, role, user) => {
    setToken(accessToken)
    setTokenState(accessToken)
    try {
      const payload = JSON.parse(atob(accessToken.split('.')[1]))
      setUsername(payload.sub)
      setRole(payload.role ?? role ?? 'user')
    } catch {
      setUsername(user ?? 'user')
      setRole(role ?? 'user')
    }
  }

  const handleLogout = () => {
    setToken(null)
    setTokenState(null)
    setUsername(null)
    setRole(null)
    setPage('main')
    setVpsList([])
    setLoading(true)
  }

  const refresh = useCallback(async (showSpinner = false) => {
    if (showSpinner) setRefreshing(true)
    try {
      const data = await fetchAllStatus()
      setVpsList(data)
      setLastUpdate(new Date())
      setError(null)
    } catch (e) {
      setError(e.message)
    } finally {
      setLoading(false)
      setRefreshing(false)
    }
  }, [])

  useEffect(() => {
    if (!token) return
    refresh()
    if (!refreshInterval) return
    const id = setInterval(() => refresh(), refreshInterval)
    return () => clearInterval(id)
  }, [refresh, token, refreshInterval])

  // Extrait le username et le rôle du token stocké au rechargement de page
  useEffect(() => {
    if (token && !username) {
      try {
        const payload = JSON.parse(atob(token.split('.')[1]))
        setUsername(payload.sub)
        setRole(payload.role ?? 'user')
      } catch { /* ignore */ }
    }
  }, [token, username])

  // Raccourcis clavier : « / » cible la recherche, « r » actualise.
  const modalOpen = !!(logsModal || updateModal || showAddVps || editVps || statsModal || deleteTarget || terminalModal)
  useEffect(() => {
    if (!token || page !== 'main' || modalOpen) return
    const onKeyDown = (e) => {
      if (e.metaKey || e.ctrlKey || e.altKey) return
      const el = e.target
      if (el instanceof HTMLElement &&
          (el.isContentEditable || ['INPUT', 'TEXTAREA', 'SELECT'].includes(el.tagName))) return

      if (e.key === '/') {
        e.preventDefault()
        searchRef.current?.focus()
      } else if (e.key.toLowerCase() === 'r') {
        e.preventDefault()
        refresh(true)
      }
    }
    window.addEventListener('keydown', onKeyDown)
    return () => window.removeEventListener('keydown', onKeyDown)
  }, [token, page, modalOpen, refresh])

  const openLogs = async (vpsId, containerId, name) => {
    setLogsModal({ vpsId, containerId, name })
    setLogsLoading(true)
    setLogsContent('')
    try {
      const data = await fetchLogs(vpsId, containerId)
      setLogsContent(data.logs)
    } catch (e) {
      setLogsContent(`Erreur lors de la récupération des logs :\n${e.message}`)
    } finally {
      setLogsLoading(false)
    }
  }

  const handleAction = async (vpsId, containerId, action) => {
    try {
      await containerAction(vpsId, containerId, action)
      toast.success(`Conteneur ${ACTION_LABELS[action] ?? action}.`)
      await refresh()
    } catch (e) {
      toast.error(`Action « ${action} » impossible : ${e.message}`)
    }
  }

  const handleUpdate = async (vpsId, project) => {
    setUpdateModal({ vpsId, project })
    setUpdateLoading(true)
    setUpdateContent('')
    try {
      const data = await composeUpdate(vpsId, project)
      setUpdateContent(data.output || '(aucune sortie)')
      toast.success(`Projet « ${project} » mis à jour.`)
    } catch (e) {
      setUpdateContent(`Erreur lors de la mise à jour :\n${e.message}`)
      toast.error(`Mise à jour de « ${project} » échouée.`)
    } finally {
      setUpdateLoading(false)
      await refresh()
    }
  }

  const handleUpdateAgent = async (vpsId) => {
    setUpdateModal({ vpsId, project: 'agent' })
    setUpdateLoading(true)
    setUpdateContent('Lancement de la mise à jour de l\'agent…\n')
    try {
      await updateAgent(vpsId)
      setUpdateContent('Mise à jour lancée. L\'agent va redémarrer dans quelques secondes.\nActualisez dans un moment pour vérifier la nouvelle version.')
      toast.info('Mise à jour de l\'agent lancée.')
    } catch (e) {
      setUpdateContent(`Erreur lors de la mise à jour de l'agent :\n${e.message}`)
      toast.error(`Mise à jour de l'agent échouée : ${e.message}`)
    } finally {
      setUpdateLoading(false)
      setTimeout(() => refresh(), 8000)
    }
  }

  const handleAddVps = async (formData) => {
    await addVps(formData)
    setShowAddVps(false)
    toast.success(`VPS « ${formData.name} » ajouté.`)
    await refresh(true)
  }

  const handleDeleteVps = async () => {
    if (!deleteTarget) return
    setDeleting(true)
    try {
      await deleteVps(deleteTarget.id)
      toast.success(`VPS « ${deleteTarget.name} » supprimé.`)
      setDeleteTarget(null)
      await refresh(true)
    } catch (e) {
      toast.error(`Suppression impossible : ${e.message}`)
    } finally {
      setDeleting(false)
    }
  }

  const handleEditVps = async (vpsId, data) => {
    await updateVps(vpsId, data)
    setEditVps(null)
    toast.success('Configuration enregistrée.')
    await refresh(true)
  }

  /** Copie la config d'un VPS ; retombe sur un téléchargement si le presse-papiers est bloqué. */
  const handleExportVps = async (vpsId) => {
    try {
      const config = await exportVps(vpsId)
      const json   = JSON.stringify(config, null, 2)
      if (await copyText(json)) {
        toast.success('Configuration copiée dans le presse-papiers.')
        return true
      }
      downloadText(`${vpsId}.json`, json, 'application/json')
      toast.info('Presse-papiers indisponible (connexion non sécurisée) — configuration téléchargée.')
      return false
    } catch (e) {
      toast.error(`Export impossible : ${e.message}`)
      return false
    }
  }

  // ─── Liste filtrée et triée ─────────────────────────────────────────────
  const allTags = useMemo(
    () => [...new Set(vpsList.flatMap(v => v.tags ?? []))].sort((a, b) => a.localeCompare(b, 'fr')),
    [vpsList],
  )

  const visibleVps = useMemo(() => {
    const query = search.trim().toLowerCase()

    const filtered = vpsList.filter(vps => {
      if (status === 'online'  && !vps.online) return false
      if (status === 'offline' && vps.online)  return false
      if (status === 'issues'  && !hasIssue(vps)) return false
      if (activeTags.length > 0 && !activeTags.every(t => (vps.tags ?? []).includes(t))) return false
      if (query && !vpsMatchesQuery(vps, query)) return false
      return true
    })

    const byName = (a, b) => a.name.localeCompare(b.name, 'fr')
    const sorters = {
      name:       byName,
      status:     (a, b) => (Number(b.online) - Number(a.online)) || (Number(hasIssue(a)) - Number(hasIssue(b))) || byName(a, b),
      cpu:        (a, b) => (b.system?.cpu_percent ?? -1) - (a.system?.cpu_percent ?? -1) || byName(a, b),
      ram:        (a, b) => (b.system?.ram_percent ?? -1) - (a.system?.ram_percent ?? -1) || byName(a, b),
      containers: (a, b) => b.containers.length - a.containers.length || byName(a, b),
    }
    return [...filtered].sort(sorters[sort] ?? byName)
  }, [vpsList, search, status, activeTags, sort])

  // Attente vérification auth
  if (!authChecked) return null

  // Pas de token → login / register
  if (!token) {
    return (
      <LoginPage
        isFirstUser={isFirstUser}
        passkeyEnabled={passkeyEnabled}
        onAuthenticated={handleAuthenticated}
      />
    )
  }

  // Le terminal donne un shell root dans le conteneur : réservé aux admins, et
  // désactivable globalement depuis la page d'administration.
  const canUseTerminal = role === 'admin' && terminalEnabled

  // Statistiques globales
  const totalOnline     = vpsList.filter(v => v.online).length
  const totalContainers = vpsList.reduce((acc, v) => acc + v.containers.length, 0)
  const totalRunning    = vpsList.reduce((acc, v) => acc + v.containers.filter(c => c.status === 'running').length, 0)
  const totalIssues     = vpsList.filter(hasIssue).length

  // ─── Pages profil / admin ───────────────────────────────────────────────
  if (page === 'profile') {
    return <ProfilePage username={username} onBack={() => setPage('main')} />
  }

  if (page === 'admin') {
    return <AdminPage onBack={() => setPage('main')} />
  }

  return (
    <div className="min-h-screen bg-gray-950 text-gray-100">
      <Header
        lastUpdate={lastUpdate}
        onRefresh={() => refresh(true)}
        onAddVps={() => setShowAddVps(true)}
        refreshing={refreshing}
        username={username}
        role={role}
        onLogout={handleLogout}
        onProfile={() => setPage('profile')}
        onAdmin={() => setPage('admin')}
        refreshInterval={refreshInterval}
        onIntervalChange={handleIntervalChange}
        intervalOptions={INTERVAL_OPTIONS}
      />

      <main className="max-w-7xl mx-auto px-4 py-6 sm:py-8">

        {/* Barre d'erreur backend */}
        {error && (
          <div className="mb-6 flex flex-wrap items-center gap-3 bg-red-950/40 border border-red-800/50 rounded-xl px-4 py-3 text-sm text-red-300">
            <span className="flex-1 min-w-[240px]">
              Impossible de joindre le backend : <span className="font-mono text-xs">{error}</span>
            </span>
            <Button variant="outline" size="sm" icon={RefreshCw} onClick={() => refresh(true)} loading={refreshing}>
              Réessayer
            </Button>
          </div>
        )}

        {/* Stats globales */}
        {!loading && vpsList.length > 0 && (
          <div className="grid grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-4 mb-6">
            {[
              { label: 'VPS en ligne',       value: `${totalOnline}/${vpsList.length}`,    color: 'text-emerald-400' },
              { label: 'Conteneurs actifs',  value: `${totalRunning}/${totalContainers}`,  color: 'text-indigo-400'  },
              { label: 'À surveiller',       value: String(totalIssues),                   color: totalIssues > 0 ? 'text-orange-400' : 'text-gray-400' },
              { label: 'Actualisation auto', value: INTERVAL_OPTIONS.find(o => o.value === refreshInterval)?.label ?? 'Off', color: 'text-gray-400' },
            ].map(({ label, value, color }) => (
              <div key={label} className="bg-gray-900 border border-gray-800 rounded-xl px-4 py-3">
                <p className={`text-2xl font-bold tabular-nums ${color}`}>{value}</p>
                <p className="text-xs text-gray-500 mt-0.5">{label}</p>
              </div>
            ))}
          </div>
        )}

        {/* Filtres */}
        {!loading && vpsList.length > 0 && (
          <DashboardToolbar
            search={search}
            onSearchChange={setSearch}
            searchRef={searchRef}
            status={status}
            onStatusChange={handleStatusChange}
            tags={allTags}
            activeTags={activeTags}
            onToggleTag={handleToggleTag}
            sort={sort}
            onSortChange={handleSortChange}
            shown={visibleVps.length}
            total={vpsList.length}
          />
        )}

        {/* Chargement initial — squelettes */}
        {loading && (
          <>
            <div className="grid grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-4 mb-6">
              {Array.from({ length: 4 }, (_, i) => <Skeleton key={i} className="h-[68px]" />)}
            </div>
            <div className="grid gap-5 lg:grid-cols-2">
              {Array.from({ length: 2 }, (_, i) => <Skeleton key={i} className="h-64" />)}
            </div>
          </>
        )}

        {/* Aucun VPS configuré */}
        {!loading && vpsList.length === 0 && !error && (
          <EmptyState
            icon={ServerCrash}
            title="Aucun VPS configuré"
            description="Ajoutez un premier serveur pour suivre ses conteneurs, ses services et sa charge en temps réel."
            action={
              <Button variant="primary" size="lg" icon={Plus} onClick={() => setShowAddVps(true)}>
                Ajouter un VPS
              </Button>
            }
          />
        )}

        {/* Aucun résultat après filtrage */}
        {!loading && vpsList.length > 0 && visibleVps.length === 0 && (
          <EmptyState
            icon={SearchX}
            title="Aucun VPS ne correspond"
            description="Aucun serveur ne correspond à la recherche ou aux filtres actifs."
            action={
              <Button
                variant="outline"
                onClick={() => { setSearch(''); handleStatusChange('all'); setActiveTags([]); localStorage.setItem('filterTags', '[]') }}
              >
                Réinitialiser les filtres
              </Button>
            }
          />
        )}

        {/* Grille de VPS */}
        {/* `items-start` : chaque carte garde sa hauteur naturelle plutôt que
            d'être étirée à celle de la plus haute de sa rangée. */}
        {!loading && visibleVps.length > 0 && (
          <div className="grid gap-5 lg:grid-cols-2 items-start">
            {visibleVps.map(vps => (
              <VpsCard
                key={vps.id}
                vps={vps}
                query={search.trim().toLowerCase()}
                onAction={handleAction}
                onLogs={openLogs}
                onDelete={() => setDeleteTarget(vps)}
                onUpdate={handleUpdate}
                onEdit={setEditVps}
                onStats={(vpsId, vpsName) => setStatsModal({ vpsId, vpsName })}
                onUpdateAgent={handleUpdateAgent}
                onExport={handleExportVps}
                onTerminal={canUseTerminal ? (target, containerRow) => setTerminalModal({ vps: target, container: containerRow }) : undefined}
              />
            ))}
          </div>
        )}
      </main>

      {/* Modal logs */}
      {logsModal && (
        <LogsModal
          name={logsModal.name}
          logs={logsContent}
          loading={logsLoading}
          onClose={() => setLogsModal(null)}
        />
      )}

      {/* Modal mise à jour compose */}
      {updateModal && (
        <LogsModal
          name={`Mise à jour — ${updateModal.project}`}
          logs={updateContent}
          loading={updateLoading}
          onClose={() => setUpdateModal(null)}
        />
      )}

      {/* Modal ajout VPS */}
      {showAddVps && (
        <AddVpsModal
          onSave={handleAddVps}
          onClose={() => setShowAddVps(false)}
        />
      )}

      {/* Modal édition VPS */}
      {editVps && (
        <EditVpsModal
          vps={editVps}
          onSave={handleEditVps}
          onClose={() => setEditVps(null)}
        />
      )}

      {/* Modal statistiques */}
      {statsModal && (
        <StatsModal
          vpsId={statsModal.vpsId}
          vpsName={statsModal.vpsName}
          onClose={() => setStatsModal(null)}
        />
      )}

      {/* Terminal interactif */}
      {terminalModal && (
        <Suspense fallback={
          <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/70 backdrop-blur-sm text-sm text-gray-400">
            Chargement du terminal…
          </div>
        }>
          <TerminalModal
            vps={terminalModal.vps}
            container={terminalModal.container}
            onClose={() => setTerminalModal(null)}
          />
        </Suspense>
      )}

      {/* Confirmation de suppression */}
      {deleteTarget && (
        <ConfirmDialog
          danger
          title="Supprimer ce VPS ?"
          message={
            <>
              <span className="text-gray-200 font-medium">{deleteTarget.name}</span>{' '}
              (<span className="font-mono text-xs">{deleteTarget.host}</span>) sera retiré de la
              configuration. Les conteneurs du serveur ne sont pas touchés.
            </>
          }
          confirmLabel="Supprimer"
          loading={deleting}
          onConfirm={handleDeleteVps}
          onCancel={() => setDeleteTarget(null)}
        />
      )}
    </div>
  )
}
