/* app.jsx — App shell with auth, API, and AI generation */

/* ── API helpers ───────────────────────────────────────────────────────────── */
async function apiFetch(url, opts = {}) {
  const res = await fetch(url, { credentials: 'same-origin', ...opts });
  if (res.status === 401) { window.location.href = '/login.html'; throw new Error('unauth'); }
  return res;
}

/* ── Debounce ──────────────────────────────────────────────────────────────── */
function useDebounce(fn, delay) {
  const timerRef = React.useRef(null);
  return React.useCallback((...args) => {
    clearTimeout(timerRef.current);
    timerRef.current = setTimeout(() => fn(...args), delay);
  }, [fn, delay]);
}

/* ── GenerateModal ─────────────────────────────────────────────────────────── */
const TIPOS = [
  'Landing page', 'Sitio web corporativo', 'Tienda en línea',
  'Estrategia SEO', 'Google Ads', 'Paquete combinado', 'Otro',
];

function GenerateModal({ onClose, onCreated }) {
  const [form, setForm] = React.useState({ empresa: '', contacto: '', email: '', tipo: '', descripcion: '', presupuesto: '' });
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState('');

  function set(k, v) { setForm(f => ({ ...f, [k]: v })); }

  async function handleSubmit(e) {
    e.preventDefault();
    if (!form.empresa || !form.tipo || !form.descripcion) { setError('Empresa, tipo y descripción son requeridos.'); return; }
    setError(''); setLoading(true);
    try {
      const genRes = await apiFetch('/api/generate.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(form),
      });
      if (!genRes.ok) { const d = await genRes.json(); setError(d.error || 'Error al generar.'); setLoading(false); return; }
      const { data } = await genRes.json();

      const today = new Date();
      const fmt = (d) => `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
      const validUntil = new Date(today); validUntil.setDate(validUntil.getDate() + 30);
      const quote = { ...data, status: 'draft', createdAt: fmt(today), validUntil: fmt(validUntil) };

      const saveRes = await apiFetch('/api/quotes.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(quote),
      });
      if (!saveRes.ok) { setError('Error al guardar la cotización.'); setLoading(false); return; }
      const { id, token } = await saveRes.json();
      onCreated({ ...quote, id, token });
    } catch (err) {
      if (err.message !== 'unauth') setError('Error de conexión. Intenta de nuevo.');
      setLoading(false);
    }
  }

  const labelStyle = { display: 'block', fontSize: 11, fontFamily: 'Poppins', fontWeight: 500, textTransform: 'uppercase', letterSpacing: '1.5px', color: 'rgba(255,255,255,0.45)', marginBottom: 6 };
  const inputStyle = { width: '100%', padding: '10px 14px', background: 'rgba(255,255,255,0.06)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: 10, color: '#fff', fontSize: 14, fontFamily: 'inherit', outline: 'none' };

  return (
    <div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.65)', zIndex: 9000, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24 }}
      onClick={(e) => e.target === e.currentTarget && onClose()}>
      <div style={{ background: '#1e1f30', border: '1px solid rgba(255,255,255,0.09)', borderRadius: 18, width: '100%', maxWidth: 520, padding: '36px 40px', maxHeight: '90vh', overflowY: 'auto' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 24 }}>
          <div>
            <div style={{ fontFamily: 'Poppins', fontWeight: 700, fontSize: 17, color: '#fff' }}>Generar con IA</div>
            <div style={{ fontSize: 13, color: 'rgba(255,255,255,0.4)', marginTop: 2 }}>Claude redactará la propuesta automáticamente</div>
          </div>
          <button onClick={onClose} style={{ background: 'none', border: 'none', color: 'rgba(255,255,255,0.4)', cursor: 'pointer', fontSize: 22, lineHeight: 1, padding: 4 }}>×</button>
        </div>

        <form onSubmit={handleSubmit} style={{ display: 'grid', gap: 18 }}>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
            <div>
              <label style={labelStyle}>Empresa *</label>
              <input style={inputStyle} value={form.empresa} onChange={e => set('empresa', e.target.value)} placeholder="Nombre del cliente" required />
            </div>
            <div>
              <label style={labelStyle}>Contacto</label>
              <input style={inputStyle} value={form.contacto} onChange={e => set('contacto', e.target.value)} placeholder="Nombre y apellido" />
            </div>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
            <div>
              <label style={labelStyle}>Email</label>
              <input style={inputStyle} type="email" value={form.email} onChange={e => set('email', e.target.value)} placeholder="correo@empresa.com" />
            </div>
            <div>
              <label style={labelStyle}>Tipo de proyecto *</label>
              <select style={{ ...inputStyle, appearance: 'none' }} value={form.tipo} onChange={e => set('tipo', e.target.value)} required>
                <option value="">Seleccionar…</option>
                {TIPOS.map(t => <option key={t} value={t}>{t}</option>)}
              </select>
            </div>
          </div>
          <div>
            <label style={labelStyle}>Descripción del proyecto *</label>
            <textarea
              style={{ ...inputStyle, resize: 'vertical', minHeight: 100 }}
              value={form.descripcion}
              onChange={e => set('descripcion', e.target.value)}
              placeholder="Describe el negocio del cliente, sus objetivos, funcionalidades clave, referencias de estilo, etc."
              required
            />
          </div>
          <div>
            <label style={labelStyle}>Presupuesto aproximado</label>
            <input style={inputStyle} value={form.presupuesto} onChange={e => set('presupuesto', e.target.value)} placeholder="Ej. $35,000 MXN (opcional)" />
          </div>

          {error && (
            <div style={{ background: 'rgba(220,38,38,0.15)', border: '1px solid rgba(220,38,38,0.3)', borderRadius: 8, padding: '10px 14px', color: '#fca5a5', fontSize: 13 }}>
              {error}
            </div>
          )}

          <div style={{ display: 'flex', gap: 10, marginTop: 4 }}>
            <button type="button" onClick={onClose} style={{ flex: 1, padding: '12px', border: '1px solid rgba(255,255,255,0.15)', borderRadius: 10, background: 'none', color: 'rgba(255,255,255,0.7)', fontFamily: 'Poppins', fontWeight: 500, fontSize: 14, cursor: 'pointer' }}>
              Cancelar
            </button>
            <button type="submit" disabled={loading} style={{ flex: 2, padding: '12px', border: 'none', borderRadius: 10, background: '#5058F2', color: '#fff', fontFamily: 'Poppins', fontWeight: 600, fontSize: 14, cursor: loading ? 'not-allowed' : 'pointer', opacity: loading ? 0.7 : 1, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8 }}>
              {loading ? (
                <>
                  <svg width="15" height="15" viewBox="0 0 24 24" fill="none" style={{ animation: 'spin 1s linear infinite' }}><circle cx="12" cy="12" r="9" stroke="rgba(255,255,255,0.3)" strokeWidth="2.5"/><path d="M12 3a9 9 0 019 9" stroke="#fff" strokeWidth="2.5" strokeLinecap="round"/></svg>
                  Generando propuesta…
                </>
              ) : (
                <><Icon.spark /> Generar propuesta</>
              )}
            </button>
          </div>
        </form>
      </div>
      <style>{`@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }`}</style>
    </div>
  );
}

/* ── App ───────────────────────────────────────────────────────────────────── */
function App() {
  const [ready, setReady] = React.useState(false);
  const [view, setView] = React.useState('dashboard'); // 'dashboard' | 'editor' | 'preview'
  const [activeId, setActiveId] = React.useState(null);
  const [quotes, setQuotes] = React.useState([]);
  const [saveState, setSaveState] = React.useState('idle'); // 'idle' | 'saving' | 'saved' | 'error'
  const [showGenerate, setShowGenerate] = React.useState(false);

  /* ── Auth check + initial load ─────────────────────────────────────────── */
  React.useEffect(() => {
    apiFetch('/api/auth-check.php')
      .then(res => { if (!res.ok) { window.location.href = '/login.html'; } else { return loadQuotes(); } })
      .catch(() => {});
  }, []);

  async function loadQuotes() {
    try {
      const res = await apiFetch('/api/quotes.php');
      const data = await res.json();
      setQuotes(Array.isArray(data) ? data : []);
      setReady(true);
    } catch {}
  }

  /* ── Auto-save ─────────────────────────────────────────────────────────── */
  const saveQuote = React.useCallback(async (quote) => {
    setSaveState('saving');
    try {
      const res = await apiFetch(`/api/quote.php?id=${encodeURIComponent(quote.id)}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(quote),
      });
      setSaveState(res.ok ? 'saved' : 'error');
      setTimeout(() => setSaveState('idle'), 2000);
    } catch { setSaveState('error'); setTimeout(() => setSaveState('idle'), 2000); }
  }, []);

  const debouncedSave = useDebounce(saveQuote, 1200);

  function updateQuote(id, fn) {
    setQuotes(prev => {
      const next = prev.map(q => q.id === id ? (typeof fn === 'function' ? fn(q) : fn) : q);
      const updated = next.find(q => q.id === id);
      if (updated) debouncedSave(updated);
      return next;
    });
  }

  /* ── New blank quote ───────────────────────────────────────────────────── */
  async function newQuote() {
    const today = new Date();
    const fmt = (d) => `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
    const validUntil = new Date(today); validUntil.setDate(validUntil.getDate() + 30);
    const fresh = {
      status: 'draft',
      createdAt: fmt(today),
      validUntil: fmt(validUntil),
      client: { company: 'Nuevo cliente', contact: '', email: '', rfc: '', address: '' },
      project: { name: 'Proyecto sin título', type: '', summary: '', startDate: '—', duration: '4 semanas' },
      scope: [],
      phases: [],
      excludes: [],
      whyUs: ['8 años diseñando experiencias digitales en CDMX', 'Proceso de revisión abierto y colaborativo en cada etapa', 'Soporte real después de la entrega, no desaparecemos'],
      nextStep: '',
      items: [],
      discount: { type: 'pct', value: 0 },
      schedule: [{ label: 'Anticipo a la firma', pct: 50 }, { label: 'Entrega final', pct: 50 }],
      terms: 'Vigencia 30 días. Incluye 2 rondas de revisión por etapa.',
    };
    try {
      const res = await apiFetch('/api/quotes.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(fresh),
      });
      const { id, token } = await res.json();
      const created = { ...fresh, id, token };
      setQuotes(prev => [created, ...prev]);
      setActiveId(id);
      setView('editor');
    } catch {}
  }

  /* ── Delete quote ──────────────────────────────────────────────────────── */
  async function deleteQuote(id) {
    try {
      await apiFetch(`/api/quote.php?id=${encodeURIComponent(id)}`, { method: 'DELETE' });
      setQuotes(prev => prev.filter(q => q.id !== id));
      if (activeId === id) { setActiveId(null); setView('dashboard'); }
    } catch {}
  }

  /* ── Duplicate quote ───────────────────────────────────────────────────── */
  async function duplicateQuote(id) {
    const src = quotes.find(q => q.id === id); if (!src) return;
    const copy = JSON.parse(JSON.stringify(src));
    delete copy.id; delete copy.token;
    copy.status = 'draft';
    copy.createdAt = new Date().toISOString().slice(0, 10);
    try {
      const res = await apiFetch('/api/quotes.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(copy),
      });
      const { id: newId, token } = await res.json();
      setQuotes(prev => [{ ...copy, id: newId, token }, ...prev]);
    } catch {}
  }

  /* ── After AI generation ───────────────────────────────────────────────── */
  function handleGenerated(quote) {
    setQuotes(prev => [quote, ...prev]);
    setActiveId(quote.id);
    setShowGenerate(false);
    setView('editor');
  }

  /* ── Logout ────────────────────────────────────────────────────────────── */
  async function logout() {
    await fetch('/api/logout.php', { credentials: 'same-origin' });
    window.location.href = '/login.html';
  }

  const active = quotes.find(q => q.id === activeId);
  const counts = {
    draft: quotes.filter(q => q.status === 'draft').length,
    sent: quotes.filter(q => q.status === 'sent').length,
    accepted: quotes.filter(q => q.status === 'accepted').length,
  };

  const saveLabel = saveState === 'saving' ? 'Guardando…' : saveState === 'saved' ? 'Guardado ✓' : saveState === 'error' ? 'Error al guardar' : '';

  if (!ready) {
    return (
      <div style={{ height: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#F5F7FA' }}>
        <div style={{ textAlign: 'center', color: '#888' }}>
          <svg width="32" height="32" viewBox="0 0 24 24" fill="none" style={{ animation: 'spin 1s linear infinite', marginBottom: 12 }}><circle cx="12" cy="12" r="9" stroke="#ddd" strokeWidth="2.5"/><path d="M12 3a9 9 0 019 9" stroke="#5058F2" strokeWidth="2.5" strokeLinecap="round"/></svg>
          <div style={{ fontFamily: 'Poppins', fontSize: 13 }}>Cargando…</div>
        </div>
        <style>{`@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }`}</style>
      </div>
    );
  }

  return (
    <div className="app">
      {/* SIDEBAR */}
      <aside className="sidebar">
        <Brand />
        <nav className="nav">
          <SectionLabel style={{color: 'rgba(255,255,255,0.4)', padding: '0 12px', marginBottom: 4}}>Trabajo</SectionLabel>
          <button className={`nav-item ${view === 'dashboard' ? 'active' : ''}`} onClick={() => setView('dashboard')}>
            <span className="dot"></span> Cotizaciones
            <span style={{marginLeft: 'auto', fontSize: 11, color: 'rgba(255,255,255,0.4)', fontWeight: 500}}>{quotes.length}</span>
          </button>
          <button className={`nav-item ${view === 'editor' ? 'active' : ''}`} onClick={() => activeId && setView('editor')}>
            <span className="dot"></span> Editor
            {activeId && <span style={{marginLeft: 'auto', fontSize: 11, color: 'rgba(255,255,255,0.4)', fontWeight: 500}}>{String(activeId).slice(-6)}</span>}
          </button>
          <button className={`nav-item ${view === 'preview' ? 'active' : ''}`} onClick={() => activeId && setView('preview')}>
            <span className="dot"></span> Vista cliente
          </button>

          <SectionLabel style={{color: 'rgba(255,255,255,0.4)', padding: '0 12px', marginBottom: 4, marginTop: 22}}>Estado</SectionLabel>
          <div style={{padding: '4px 12px', display: 'grid', gap: 10, fontSize: 12.5}}>
            <div style={{display: 'flex', justifyContent: 'space-between', color: 'rgba(255,255,255,0.7)'}}><span>Borradores</span><span className="poppins" style={{fontWeight: 600}}>{counts.draft}</span></div>
            <div style={{display: 'flex', justifyContent: 'space-between', color: 'rgba(255,255,255,0.7)'}}><span>Enviadas</span><span className="poppins" style={{fontWeight: 600}}>{counts.sent}</span></div>
            <div style={{display: 'flex', justifyContent: 'space-between', color: 'rgba(255,255,255,0.7)'}}><span>Aceptadas</span><span className="poppins" style={{fontWeight: 600}}>{counts.accepted}</span></div>
          </div>
        </nav>

        <div className="sidebar-foot">
          {saveLabel && (
            <div style={{ fontSize: 11.5, color: saveState === 'error' ? '#fca5a5' : 'rgba(255,255,255,0.45)', fontFamily: 'Poppins', marginBottom: 10, paddingLeft: 4 }}>
              {saveLabel}
            </div>
          )}
          <button onClick={logout} style={{ width: '100%', padding: '9px 14px', background: 'rgba(255,255,255,0.06)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: 10, color: 'rgba(255,255,255,0.5)', fontFamily: 'Poppins', fontWeight: 500, fontSize: 12.5, cursor: 'pointer', textAlign: 'left' }}>
            Cerrar sesión
          </button>
        </div>
      </aside>

      {/* MAIN */}
      <main className={view === 'preview' ? '' : 'main'} style={view === 'preview' ? {padding: 0} : {}}>
        {view === 'dashboard' && (
          <Dashboard
            quotes={quotes}
            openQuote={(id) => { setActiveId(id); setView('editor'); }}
            openPreview={(id) => { setActiveId(id); setView('preview'); }}
            newQuote={newQuote}
            duplicateQuote={duplicateQuote}
            deleteQuote={deleteQuote}
            onGenerate={() => setShowGenerate(true)}
          />
        )}
        {view === 'editor' && active && (
          <Editor
            quote={active}
            updateQuote={updateQuote}
            openPreview={(id) => { setActiveId(id); setView('preview'); }}
            back={() => setView('dashboard')}
          />
        )}
        {view === 'preview' && active && (
          <Preview
            quote={active}
            back={() => setView('dashboard')}
            openEditor={(id) => { setActiveId(id); setView('editor'); }}
          />
        )}
      </main>

      {/* AI GENERATION MODAL */}
      {showGenerate && (
        <GenerateModal
          onClose={() => setShowGenerate(false)}
          onCreated={handleGenerated}
        />
      )}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
