import { useState, useEffect, useCallback, useRef } from 'react';
import { api } from '../../api.js';

function SectionHeader({ title, description }) {
  return (
    <div style={{ marginBottom: 28 }}>
      <h2 style={{ margin: '0 0 6px', fontSize: 20, fontWeight: 700, color: 'var(--text)' }}>{title}</h2>
      {description && <p style={{ margin: 0, color: 'var(--text-muted)', fontSize: 14 }}>{description}</p>}
    </div>
  );
}

function MenuBtn({ onClick, icon, label, danger = false }) {
  return (
    <button
      style={{ display: 'flex', alignItems: 'center', gap: 8, width: '100%', padding: '8px 14px', background: 'none', border: 'none', cursor: 'pointer', fontSize: 'var(--fs-sm)', color: danger ? 'var(--danger)' : 'var(--text)', textAlign: 'left' }}
      onMouseEnter={e => e.currentTarget.style.background = 'var(--surface-2)'}
      onMouseLeave={e => e.currentTarget.style.background = 'none'}
      onClick={onClick}
    >
      {icon}{label}
    </button>
  );
}

function IcoDownload() {
  return <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>;
}
function IcoTrash() {
  return <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6M14 11v6"/><path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/></svg>;
}
function IcoRestore() {
  return <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-4.95"/></svg>;
}

function fmtSize(bytes) {
  if (bytes < 1024) return `${bytes} o`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} Ko`;
  return `${(bytes / (1024 * 1024)).toFixed(1)} Mo`;
}

function fmtDate(iso) {
  const d = new Date(iso);
  return d.toLocaleDateString('fr-FR', { day: '2-digit', month: '2-digit', year: 'numeric' })
    + ' ' + d.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' });
}

function fmtRunAt(iso) {
  if (!iso) return '—';
  const d = new Date(iso);
  return d.toLocaleDateString('fr-FR', { day: '2-digit', month: '2-digit', year: 'numeric' })
    + ' ' + d.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
}

/** Attend que /api/health réponde, avec retry toutes les 2s pendant max 60s */
async function pollUntilReady(maxMs = 60000) {
  const base = import.meta.env.VITE_API_URL || '/api';
  const deadline = Date.now() + maxMs;
  while (Date.now() < deadline) {
    await new Promise(r => setTimeout(r, 2000));
    try {
      const res = await fetch(base + '/health');
      if (res.ok) return true;
    } catch { /* serveur pas encore prêt */ }
  }
  return false;
}

export default function ExportSection() {
  const [generating, setGenerating]   = useState(false);
  const [genErr, setGenErr]           = useState(null);
  const [exports, setExports]         = useState([]);
  const [loadingList, setLoadingList] = useState(true);
  const [openMenu, setOpenMenu]       = useState(null);
  const [uploading, setUploading]     = useState(false);
  const [uploadErr, setUploadErr]     = useState(null);
  const [jobLogs, setJobLogs]         = useState([]);
  const [loadingLogs, setLoadingLogs] = useState(true);
  const [runningJob, setRunningJob]   = useState(false);
  const [restoring, setRestoring]     = useState(null); // filename en cours
  const [restoreConfirm, setRestoreConfirm] = useState(null); // filename à confirmer
  const [restarting, setRestarting]   = useState(false); // écran "serveur redémarre"
  const fileInputRef                  = useRef(null);

  const loadExports = useCallback(() => {
    setLoadingList(true);
    api.get('/admin/exports')
      .then(setExports)
      .catch(() => setExports([]))
      .finally(() => setLoadingList(false));
  }, []);

  const loadJobLogs = useCallback(() => {
    setLoadingLogs(true);
    api.get('/admin/job-logs', { job: 'auto_export', limit: 20 })
      .then(d => setJobLogs(d.rows || []))
      .catch(() => setJobLogs([]))
      .finally(() => setLoadingLogs(false));
  }, []);

  async function runJobNow() {
    setRunningJob(true);
    try {
      await api.post('/admin/jobs/auto_export/run', {});
      loadExports();
      loadJobLogs();
    } catch (e) {
      alert(e.message || "Erreur lors de l'exécution manuelle");
    } finally {
      setRunningJob(false);
    }
  }

  useEffect(() => { loadExports(); }, [loadExports]);
  useEffect(() => { loadJobLogs(); }, [loadJobLogs]);

  useEffect(() => {
    if (!openMenu) return;
    const close = () => setOpenMenu(null);
    window.addEventListener('scroll', close, true);
    return () => window.removeEventListener('scroll', close, true);
  }, [openMenu]);

  async function handleGenerate() {
    setGenerating(true);
    setGenErr(null);
    try {
      const blob = await api.blob('/admin/export-full');
      const url  = URL.createObjectURL(blob);
      const a    = document.createElement('a');
      a.href     = url;
      const d    = new Date();
      const ymd  = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
      a.download = `crowdlending-export-${ymd}.zip`;
      a.click();
      URL.revokeObjectURL(url);
      loadExports();
    } catch (e) {
      setGenErr(e.message || "Erreur lors de la génération de l'export");
    } finally {
      setGenerating(false);
    }
  }

  async function handleDownload(filename) {
    setOpenMenu(null);
    try {
      const blob = await api.blob(`/admin/exports/${encodeURIComponent(filename)}`);
      const url  = URL.createObjectURL(blob);
      const a    = document.createElement('a');
      a.href     = url;
      a.download = filename;
      a.click();
      URL.revokeObjectURL(url);
    } catch (e) {
      alert(e.message || 'Erreur lors du téléchargement');
    }
  }

  async function handleDelete(filename) {
    setOpenMenu(null);
    try {
      await api.del(`/admin/exports/${encodeURIComponent(filename)}`);
      loadExports();
    } catch (e) {
      alert(e.message || 'Erreur lors de la suppression');
    }
  }

  async function handleUpload(e) {
    const file = e.target.files?.[0];
    if (!file) return;
    e.target.value = '';
    setUploading(true);
    setUploadErr(null);
    try {
      const formData = new FormData();
      formData.append('file', file);
      const result = await api.upload('/admin/exports/upload', formData);
      setExports(result.exports);
    } catch (err) {
      setUploadErr(err.message || "Erreur lors de l'import");
    } finally {
      setUploading(false);
    }
  }

  async function confirmRestore(filename) {
    setOpenMenu(null);
    setRestoreConfirm(filename);
  }

  async function executeRestore() {
    const filename = restoreConfirm;
    setRestoreConfirm(null);
    setRestoring(filename);
    try {
      await api.post(`/admin/exports/${encodeURIComponent(filename)}/restore`, {});
      // Le serveur va redémarrer — on affiche l'écran d'attente
      setRestarting(true);
      const ok = await pollUntilReady(90000);
      if (ok) {
        window.location.href = '/';
      } else {
        setRestarting(false);
        alert('Le serveur ne répond pas après 90 secondes. Vérifiez les logs.');
      }
    } catch (e) {
      setRestoring(null);
      alert(e.message || 'Erreur lors de la restauration');
    }
  }

  const openMenuFor = (e, filename) => {
    e.stopPropagation();
    const rect = e.currentTarget.getBoundingClientRect();
    setOpenMenu({ filename, x: rect.right, y: rect.bottom });
  };

  // ── Écran "serveur en cours de redémarrage" ────────────────────────────────
  if (restarting) {
    return (
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 20, padding: '80px 0', textAlign: 'center' }}>
        <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="var(--primary)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={{ animation: 'spin 1.2s linear infinite' }}>
          <polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-4.95"/>
        </svg>
        <style>{`@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }`}</style>
        <div>
          <div style={{ fontWeight: 700, fontSize: 18, color: 'var(--text)', marginBottom: 8 }}>Restauration en cours…</div>
          <div style={{ color: 'var(--text-muted)', fontSize: 14 }}>Le serveur redémarre. Vous serez redirigé automatiquement.</div>
        </div>
      </div>
    );
  }

  return (
    <div>
      <SectionHeader
        title="Export complet"
        description="Génère une archive ZIP de la base de données et des assets. L'export est téléchargé dans le navigateur et conservé sur le serveur (10 derniers)."
      />

      {/* Bloc génération */}
      <div className="card" style={{ padding: '20px 24px', marginBottom: 24, display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16, flexWrap: 'wrap' }}>
        <div>
          <div style={{ fontWeight: 600, color: 'var(--text)', marginBottom: 4 }}>Nouvel export</div>
          <div style={{ fontSize: 13, color: 'var(--text-muted)' }}>
            Inclut : <code>crowdlending.db</code>, <code>logos/</code>, <code>icons/</code>, <code>manifest.json</code>
          </div>
          {genErr && <div className="error" style={{ marginTop: 8 }}>{genErr}</div>}
        </div>
        <button className="btn-primary" onClick={() => handleGenerate()} disabled={generating} style={{ flexShrink: 0 }}>
          {generating ? 'Export en cours…' : 'Générer et télécharger'}
        </button>
      </div>

      {/* En-tête liste */}
      <input ref={fileInputRef} type="file" accept=".zip,application/zip" style={{ display: 'none' }} onChange={handleUpload} />
      <div style={{ marginBottom: 8, display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>
        <div>
          <span style={{ fontWeight: 600, color: 'var(--text)', fontSize: 15 }}>Fichiers disponibles sur le serveur</span>
          {uploadErr && <div className="error" style={{ marginTop: 4, fontSize: 13 }}>{uploadErr}</div>}
        </div>
        <button className="btn-secondary" onClick={() => fileInputRef.current?.click()} disabled={uploading} style={{ flexShrink: 0, display: 'flex', alignItems: 'center', gap: 6 }}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
          {uploading ? 'Import en cours…' : 'Importer'}
        </button>
      </div>

      {/* Liste */}
      {loadingList ? (
        <div style={{ color: 'var(--text-muted)', fontSize: 14, padding: '12px 0' }}>Chargement…</div>
      ) : exports.length === 0 ? (
        <div className="card" style={{ padding: '20px 24px', color: 'var(--text-muted)', fontSize: 14 }}>Aucun export disponible.</div>
      ) : (
        <div className="card" style={{ overflow: 'hidden', padding: 0 }}>
          <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 14 }}>
            <thead>
              <tr style={{ borderBottom: '1px solid var(--border)', background: 'var(--surface-2)' }}>
                <th style={{ padding: '10px 16px', textAlign: 'left', fontWeight: 600, color: 'var(--text-muted)' }}>Fichier</th>
                <th style={{ padding: '10px 16px', textAlign: 'left', fontWeight: 600, color: 'var(--text-muted)' }}>Date</th>
                <th style={{ padding: '10px 16px', textAlign: 'right', fontWeight: 600, color: 'var(--text-muted)' }}>Taille</th>
                <th style={{ padding: '10px 16px', width: 48 }} />
              </tr>
            </thead>
            <tbody>
              {exports.map((exp, i) => (
                <tr key={exp.filename} style={{ borderBottom: i < exports.length - 1 ? '1px solid var(--border)' : 'none', opacity: restoring === exp.filename ? 0.5 : 1 }}>
                  <td style={{ padding: '12px 16px', color: 'var(--text)', fontFamily: 'monospace', fontSize: 13 }}>{exp.filename}</td>
                  <td style={{ padding: '12px 16px', color: 'var(--text-muted)' }}>{fmtDate(exp.created_at)}</td>
                  <td style={{ padding: '12px 16px', color: 'var(--text-muted)', textAlign: 'right' }}>{fmtSize(exp.size)}</td>
                  <td style={{ padding: '12px 16px', textAlign: 'right' }}>
                    <button onClick={e => openMenuFor(e, exp.filename)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--text-muted)', padding: '4px 6px', borderRadius: 4, display: 'flex', alignItems: 'center' }}>
                      <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><circle cx="12" cy="5" r="1.5"/><circle cx="12" cy="12" r="1.5"/><circle cx="12" cy="19" r="1.5"/></svg>
                    </button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      {/* Menu ⋮ contextuel */}
      {openMenu && (
        <>
          <div style={{ position: 'fixed', inset: 0, zIndex: 299 }} onClick={() => setOpenMenu(null)} />
          <div style={{ position: 'fixed', left: openMenu.x, top: openMenu.y, transform: 'translateX(-100%) translateY(4px)', zIndex: 300, background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 8, boxShadow: '0 4px 20px rgba(0,0,0,0.15)', padding: '4px 0', minWidth: 180 }}>
            <MenuBtn icon={<IcoDownload />} label="Télécharger" onClick={() => handleDownload(openMenu.filename)} />
            <MenuBtn icon={<IcoRestore />} label="Restaurer" onClick={() => confirmRestore(openMenu.filename)} />
            <div style={{ height: 1, background: 'var(--border)', margin: '4px 0' }} />
            <MenuBtn icon={<IcoTrash />} label="Supprimer" danger onClick={() => handleDelete(openMenu.filename)} />
          </div>
        </>
      )}

      {/* Panel logs du job automatique */}
      <div style={{ marginTop: 32 }}>
        <div style={{ marginBottom: 8, display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>
          <div>
            <span style={{ fontWeight: 600, color: 'var(--text)', fontSize: 15 }}>Job automatique — 3h00</span>
            <span style={{ marginLeft: 10, fontSize: 12, color: 'var(--text-muted)', background: 'var(--surface-2)', padding: '2px 8px', borderRadius: 10, border: '1px solid var(--border)' }}>auto_export</span>
          </div>
          <button
            className="btn-secondary"
            onClick={() => runJobNow()}
            disabled={runningJob}
            style={{ flexShrink: 0, display: 'flex', alignItems: 'center', gap: 6 }}
          >
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polygon points="5 3 19 12 5 21 5 3"/></svg>
            {runningJob ? 'Exécution…' : 'Exécuter maintenant'}
          </button>
        </div>

        {loadingLogs ? (
          <div style={{ color: 'var(--text-muted)', fontSize: 14, padding: '10px 0' }}>Chargement…</div>
        ) : jobLogs.length === 0 ? (
          <div className="card" style={{ padding: '16px 20px', color: 'var(--text-muted)', fontSize: 14 }}>
            Aucune exécution enregistrée.
          </div>
        ) : (
          <div className="card" style={{ overflow: 'hidden', padding: 0 }}>
            <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
              <thead>
                <tr style={{ borderBottom: '1px solid var(--border)', background: 'var(--surface-2)' }}>
                  <th style={{ padding: '9px 14px', textAlign: 'left', fontWeight: 600, color: 'var(--text-muted)' }}>Date</th>
                  <th style={{ padding: '9px 14px', textAlign: 'left', fontWeight: 600, color: 'var(--text-muted)' }}>Statut</th>
                  <th style={{ padding: '9px 14px', textAlign: 'left', fontWeight: 600, color: 'var(--text-muted)' }}>Détails</th>
                </tr>
              </thead>
              <tbody>
                {jobLogs.map((log, i) => (
                  <tr key={log.id} style={{ borderBottom: i < jobLogs.length - 1 ? '1px solid var(--border)' : 'none' }}>
                    <td style={{ padding: '10px 14px', color: 'var(--text-muted)', whiteSpace: 'nowrap' }}>
                      {fmtRunAt(log.run_at)}
                    </td>
                    <td style={{ padding: '10px 14px' }}>
                      <span style={{
                        fontSize: 12, fontWeight: 600, padding: '2px 8px', borderRadius: 10,
                        background: log.status === 'ok' ? 'color-mix(in srgb, var(--success) 15%, transparent)' : 'color-mix(in srgb, var(--danger) 15%, transparent)',
                        color: log.status === 'ok' ? 'var(--success)' : 'var(--danger)',
                      }}>
                        {log.status === 'ok' ? '✓ Succès' : '✗ Erreur'}
                      </span>
                    </td>
                    <td style={{ padding: '10px 14px', color: log.error_msg ? 'var(--danger)' : 'var(--text-muted)', fontSize: 12 }}>
                      {log.error_msg || log.details || '—'}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        )}
      </div>

      {/* Modale de confirmation restauration */}
      {restoreConfirm && (
        <>
          <div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.4)', zIndex: 399 }} onClick={() => setRestoreConfirm(null)} />
          <div style={{ position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%,-50%)', zIndex: 400, background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 12, boxShadow: '0 8px 32px rgba(0,0,0,0.2)', padding: 28, width: 460, maxWidth: '90vw' }}>
            <div style={{ fontWeight: 700, fontSize: 17, color: 'var(--text)', marginBottom: 12 }}>Restaurer cet export ?</div>
            <div style={{ fontSize: 14, color: 'var(--text-muted)', marginBottom: 8, lineHeight: 1.6 }}>
              L'environnement courant sera <strong style={{ color: 'var(--text)' }}>remplacé</strong> par le contenu de :
            </div>
            <div style={{ fontFamily: 'monospace', fontSize: 13, background: 'var(--surface-2)', padding: '8px 12px', borderRadius: 6, marginBottom: 16 }}>{restoreConfirm}</div>
            <div style={{ fontSize: 13, color: 'var(--text-muted)', marginBottom: 20, padding: '10px 14px', background: 'color-mix(in srgb, var(--warning, #f59e0b) 10%, transparent)', borderRadius: 6, lineHeight: 1.6 }}>
              ⚠️ Un backup automatique de l'état actuel sera créé avant la restauration. Le serveur redémarrera automatiquement.
            </div>
            <div style={{ display: 'flex', gap: 10, justifyContent: 'flex-end' }}>
              <button className="btn-secondary" onClick={() => setRestoreConfirm(null)}>Annuler</button>
              <button className="btn-danger" onClick={() => executeRestore()} style={{ background: 'var(--danger)', color: '#fff', border: 'none', borderRadius: 6, padding: '8px 18px', cursor: 'pointer', fontWeight: 600 }}>
                Restaurer
              </button>
            </div>
          </div>
        </>
      )}
    </div>
  );
}
