// app-main.jsx — Générateur de posts NOMADE

const { useState, useEffect, useRef, useMemo, useCallback } = React;

// ── Field ──────────────────────────────────────────────────────────────────
function Field({ label, hint, children }) {
  return (
    <div style={{ marginBottom: 16 }}>
      <label style={{
        display: 'block',
        fontFamily: window.N.mono, fontSize: 10, letterSpacing: '0.28em',
        color: 'rgba(236,227,212,0.55)', textTransform: 'uppercase',
        marginBottom: 6, fontWeight: 500,
      }}>{label}</label>
      {children}
      {hint && <div style={{ fontSize: 11, color: 'rgba(236,227,212,0.35)', marginTop: 4, fontFamily: window.N.body }}>{hint}</div>}
    </div>
  );
}

// ── URL Importer ───────────────────────────────────────────────────────────
async function fetchViaProxy(url) {
  const enc = encodeURIComponent(url);
  const proxies = [
    { url: 'https://api.codetabs.com/v1/proxy/?quest=' + enc, json: false },
    { url: 'https://api.allorigins.win/get?url=' + enc, json: true },
    { url: 'https://api.allorigins.win/raw?url=' + enc, json: false },
  ];
  for (const p of proxies) {
    try {
      const res = await fetch(p.url);
      if (!res.ok) continue;
      if (p.json) {
        const data = await res.json();
        if (data?.contents && data.contents.length > 200) return data.contents;
      } else {
        const text = await res.text();
        if (text && text.length > 200) return text;
      }
    } catch (e) { /* try next */ }
  }
  throw new Error('Toutes les méthodes de récupération ont échoué');
}

async function fetchImageBlob(url) {
  const enc = encodeURIComponent(url);
  const proxies = [
    'https://api.codetabs.com/v1/proxy/?quest=' + enc,
    'https://api.allorigins.win/raw?url=' + enc,
    url,
  ];
  for (const p of proxies) {
    try {
      const res = await fetch(p);
      if (!res.ok) continue;
      const blob = await res.blob();
      if (blob.type && (blob.type.startsWith('image/') || blob.size > 1000)) return blob;
    } catch (e) { /* try next */ }
  }
  throw new Error('Image inaccessible');
}

function ImportTab({ onPickImage }) {
  const [url, setUrl] = useState('');
  const [loading, setLoading] = useState(false);
  const [picking, setPicking] = useState(null);
  const [error, setError] = useState('');
  const [images, setImages] = useState([]);

  const isDirectImageURL = (u) => /\.(jpg|jpeg|png|webp|gif|avif)(\?|#|$)/i.test(u);

  const runFetch = async () => {
    const u = url.trim();
    if (!u) { setError('Colle une URL.'); return; }
    setLoading(true); setError(''); setImages([]);
    try {
      if (isDirectImageURL(u)) {
        setImages([{ src: u, label: 'Image directe' }]);
        setLoading(false);
        return;
      }
      const html = await fetchViaProxy(u);
      const doc = new DOMParser().parseFromString(html, 'text/html');
      const base = doc.querySelector('base')?.href || u;
      const resolve = (s) => { try { return new URL(s, base).href; } catch { return s; } };
      const found = new Map();
      const add = (src, label, priority) => {
        if (!src) return;
        const r = resolve(src);
        if (!r.startsWith('http')) return;
        if (!found.has(r) || found.get(r).priority < priority) {
          found.set(r, { src: r, label, priority });
        }
      };
      doc.querySelectorAll('meta[property^="og:image"], meta[name^="twitter:image"], meta[property^="al:"]').forEach(m => {
        add(m.getAttribute('content'), 'OG image', 10);
      });
      doc.querySelectorAll('link[rel="image_src"]').forEach(l => add(l.getAttribute('href'), 'link image_src', 9));
      doc.querySelectorAll('script[type="application/ld+json"]').forEach(s => {
        try {
          const j = JSON.parse(s.textContent);
          const items = Array.isArray(j) ? j : [j];
          items.forEach(it => {
            const im = it.image;
            if (typeof im === 'string') add(im, 'JSON-LD', 8);
            else if (Array.isArray(im)) im.forEach(i => add(typeof i === 'string' ? i : i.url, 'JSON-LD', 8));
            else if (im?.url) add(im.url, 'JSON-LD', 8);
            if (it.thumbnailUrl) add(it.thumbnailUrl, 'thumbnail', 7);
          });
        } catch (e) {}
      });
      doc.querySelectorAll('img').forEach(img => {
        const s = img.getAttribute('src') || img.getAttribute('data-src') || img.getAttribute('data-original');
        add(s, '<img>', 1);
        const srcset = img.getAttribute('srcset');
        if (srcset) {
          const candidates = srcset.split(',').map(c => c.trim().split(/\s+/));
          if (candidates.length) {
            const largest = candidates.reduce((a, b) => {
              const aw = parseFloat(a[1]) || 0; const bw = parseFloat(b[1]) || 0;
              return bw > aw ? b : a;
            });
            add(largest[0], '<img srcset>', 2);
          }
        }
      });
      const sorted = [...found.values()]
        .sort((a, b) => b.priority - a.priority)
        .filter(i => !/favicon|sprite|emoji|tracker|pixel/i.test(i.src));
      if (!sorted.length) {
        setError('Aucune image trouvée sur cette page.');
      } else {
        setImages(sorted.slice(0, 24));
      }
    } catch (e) {
      console.error(e);
      setError('Erreur — l\'URL n\'est peut-être pas accessible. Instagram bloque souvent le scraping; essaie un lien d\'image directe ou un autre site.');
    }
    setLoading(false);
  };

  const pickImage = async (imgUrl) => {
    setPicking(imgUrl);
    setError('');
    try {
      const blob = await fetchImageBlob(imgUrl);
      const reader = new FileReader();
      reader.onload = () => {
        onPickImage(reader.result);
        setPicking(null);
      };
      reader.onerror = () => {
        setError('Impossible de lire l\'image.');
        setPicking(null);
      };
      reader.readAsDataURL(blob);
    } catch (e) {
      setError('Impossible de télécharger cette image — CORS bloque.');
      setPicking(null);
    }
  };

  return (
    <div>
      <div style={{
        padding: 16,
        background: 'linear-gradient(135deg, rgba(142,69,39,0.16) 0%, rgba(193,106,67,0.12) 100%)',
        border: '1px solid rgba(193,106,67,0.3)',
        borderRadius: 12,
        marginBottom: 18,
      }}>
        <div style={{
          fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.3em',
          color: '#CFBFA4', textTransform: 'uppercase', marginBottom: 10, fontWeight: 600,
        }}>🔗 Import depuis une URL</div>
        <Textarea
          placeholder="https://www.instagram.com/p/...\nou URL d'image directe\nou page web (Spotify, Apple Music, blog...)"
          value={url}
          onChange={e => setUrl(e.target.value)}
          style={{ minHeight: 70, fontSize: 12, background: 'rgba(0,0,0,0.25)' }}
        />
        <button
          onClick={runFetch}
          disabled={loading}
          style={{
            width: '100%', marginTop: 10,
            padding: '12px 18px',
            background: loading ? 'rgba(193,106,67,0.4)' : 'linear-gradient(135deg, #8E4527 0%, #C16A43 70%, #D58A62 110%)',
            border: 'none', borderRadius: 8,
            color: '#0C0A08',
            fontFamily: 'Space Grotesk', fontWeight: 700, fontSize: 13,
            letterSpacing: '0.16em', textTransform: 'uppercase',
            cursor: loading ? 'wait' : 'pointer',
          }}>
          {loading ? '⟳ Récupération…' : '⬇  Récupérer les images'}
        </button>
        {error && <div style={{ marginTop: 8, fontSize: 12, color: '#ff9c8c', lineHeight: 1.4 }}>{error}</div>}
      </div>

      {images.length > 0 && (
        <Field label={`— ${images.length} image(s) trouvée(s)`} hint="Click sur celle à utiliser">
          <div style={{
            display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8,
            maxHeight: 'calc(100vh - 400px)', overflowY: 'auto', padding: 2,
          }}>
            {images.map((img, i) => (
              <button key={i}
                onClick={() => pickImage(img.src)}
                disabled={picking !== null}
                title={img.src}
                style={{
                  padding: 0,
                  background: '#000',
                  border: picking === img.src ? '2px solid #C16A43' : '1px solid rgba(236,227,212,0.1)',
                  borderRadius: 8,
                  cursor: picking !== null ? 'wait' : 'pointer',
                  overflow: 'hidden',
                  aspectRatio: '1',
                  position: 'relative',
                  transition: 'all 150ms',
                }}
                onMouseEnter={e => { if (picking === null) e.currentTarget.style.borderColor = 'rgba(193,106,67,0.6)'; }}
                onMouseLeave={e => { if (picking === null) e.currentTarget.style.borderColor = 'rgba(236,227,212,0.1)'; }}>
                <img src={img.src} alt="" referrerPolicy="no-referrer"
                  style={{ width: '100%', height: '100%', objectFit: 'cover' }}
                  onError={e => { e.currentTarget.parentNode.style.display = 'none'; }} />
                {picking === img.src && (
                  <div style={{
                    position: 'absolute', inset: 0,
                    background: 'rgba(193,106,67,0.85)',
                    display: 'flex', alignItems: 'center', justifyContent: 'center',
                    color: '#0C0A08', fontFamily: 'JetBrains Mono', fontSize: 11, letterSpacing: '0.2em',
                  }}>⟳ ...</div>
                )}
              </button>
            ))}
          </div>
        </Field>
      )}
    </div>
  );
}

const inputStyle = {
  width: '100%',
  padding: '11px 14px',
  background: 'rgba(236,227,212,0.04)',
  border: '1px solid rgba(236,227,212,0.12)',
  borderRadius: 8,
  color: '#ECE3D4',
  fontFamily: 'Inter, system-ui, sans-serif',
  fontSize: 14,
  outline: 'none',
  transition: 'border-color 150ms',
};

function Input(props) {
  return <input {...props} style={{ ...inputStyle, ...(props.style || {}) }}
    onFocus={e => e.target.style.borderColor = 'rgba(193,106,67,0.55)'}
    onBlur={e => e.target.style.borderColor = 'rgba(236,227,212,0.12)'} />;
}

function Textarea(props) {
  return <textarea {...props} style={{ ...inputStyle, fontFamily: 'Inter, system-ui, sans-serif', resize: 'vertical', minHeight: 60, ...(props.style || {}) }}
    onFocus={e => e.target.style.borderColor = 'rgba(193,106,67,0.55)'}
    onBlur={e => e.target.style.borderColor = 'rgba(236,227,212,0.12)'} />;
}

// ── Template picker ────────────────────────────────────────────────────────
function TemplatePicker({ value, onChange }) {
  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 8 }}>
      {window.TEMPLATES.map(t => {
        const active = value === t.id;
        return (
          <button key={t.id}
            onClick={() => onChange(t.id)}
            style={{
              padding: '14px 14px',
              background: active ? 'rgba(193,106,67,0.16)' : 'rgba(236,227,212,0.03)',
              border: `1px solid ${active ? 'rgba(193,106,67,0.6)' : 'rgba(236,227,212,0.1)'}`,
              borderRadius: 10,
              cursor: 'pointer',
              textAlign: 'left',
              transition: 'all 150ms',
              boxShadow: active ? '0 0 16px rgba(193,106,67,0.2)' : 'none',
            }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 4 }}>
              <span style={{ color: '#CFBFA4', fontSize: 16 }}>{t.icon}</span>
              <div style={{ fontFamily: 'Space Grotesk, sans-serif', fontWeight: 600, fontSize: 13, color: '#ECE3D4' }}>{t.name}</div>
            </div>
            <div style={{ fontSize: 11, color: 'rgba(236,227,212,0.5)' }}>{t.description}</div>
          </button>
        );
      })}
    </div>
  );
}

// ── AI Generation ──────────────────────────────────────────────────────────
async function callClaudeAPI(systemPrompt, apiKey) {
  if (!apiKey) throw new Error('NO_KEY');
  const res = await fetch('https://api.anthropic.com/v1/messages', {
    method: 'POST',
    headers: {
      'x-api-key': apiKey,
      'anthropic-version': '2023-06-01',
      'anthropic-dangerous-direct-browser-access': 'true',
      'content-type': 'application/json',
    },
    body: JSON.stringify({
      model: 'claude-haiku-4-5-20251001',
      max_tokens: 1024,
      messages: [{ role: 'user', content: systemPrompt }],
    }),
  });
  if (!res.ok) {
    const errText = await res.text();
    if (res.status === 401) throw new Error('INVALID_KEY');
    throw new Error('API ' + res.status + ': ' + errText.slice(0, 160));
  }
  const data = await res.json();
  return data.content?.[0]?.text || '';
}

function extractJSON(response) {
  let jsonText = response.trim().replace(/^```(?:json)?\s*/i, '').replace(/\s*```$/i, '');
  const start = jsonText.indexOf('{');
  const end = jsonText.lastIndexOf('}');
  if (start >= 0 && end >= 0) jsonText = jsonText.substring(start, end + 1);
  return JSON.parse(jsonText);
}

async function generateWithAI(prompt, templateType, apiKey) {
  const tplName = window.TEMPLATES.find(t => t.id === templateType)?.name || 'custom';
  const isCertif = templateType === 'certif';

  const brand = `NOMADE est un label de musique indépendant (rap, afropop, RnB, trap mélodique). Identité : sobre, cinématique, dark mode. Couleurs noir mat / bronze-or / beige sable. Signature : "Un son, une trace." Ton premium, urbain, français, jamais clinquant.`;

  if (isCertif) {
    const systemPrompt = `Tu es copywriter pour les posts Instagram de NOMADE (label musical).
${brand}

L'utilisateur veut annoncer une CERTIFICATION (disque d'or/platine/diamant): "${prompt}"

Réponds UNIQUEMENT en JSON strict (pas de markdown):
{
  "certifFormat": "album" | "single",
  "certifType": "OR" | "PLATINE" | "DIAMANT",
  "pill": "string",          // ex: "CERTIFIÉ", "OR · 2026"
  "kicker": "string",        // ex: "/ CERTIFICATION", "/ DISQUE D'OR"
  "artistName": "string",    // Nom artiste/groupe en MAJUSCULES
  "albumName": "string",     // Nom album/single
  "salesNumber": "string",   // ventes album (ex: "50.000") ou streams single (ex: "15.000.000")
  "bottomCopy": "string",    // 2 lignes du bas séparées par \\n, ton premium/sobre
  "ctaLabel": "string",      // ex: "/ Vos projets chez NOMADE"
  "ctaUrl": "nomadeclan.com"
}`;
    const response = await callClaudeAPI(systemPrompt, apiKey);
    return { layout: 'certif', ...extractJSON(response) };
  }

  const systemPrompt = `Tu es copywriter pour les posts Instagram de NOMADE (label musical).
${brand}

Style: punchy, court, français, ton label premium / urbain / cinématique. Utilise des points/italiques.

L'utilisateur veut annoncer (catégorie "${tplName}"): "${prompt}"

Réponds UNIQUEMENT en JSON strict (pas de markdown, pas de texte avant/après) avec ces clés exactes:
{
  "pill": "string",          // Pastille top-droite, 1-3 mots max, MAJUSCULES, ex: "SIGNÉ · NOMADE", "OUT NOW", "EN STUDIO"
  "kicker": "string",        // Étiquette mono haut, ex: "/ NOUVELLE SIGNATURE", "/ NOUVELLE SORTIE", "/ SESSION · 01"
  "headline": "string",      // Titre principal, court (souvent un nom + point), ex: "Davy."
  "subtitle": "string",      // Sous-titre italique, 2-5 mots, ex: "rejoint NOMADE."
  "storyTop": "string",      // Ligne 1 titre STORY, 1-2 mots, ex: "Bienvenue"
  "storyBottom": "string",   // Ligne 2 titre STORY italique, 1-2 mots, ex: "Davy."
  "chips": ["string","string","string"],  // 3 tags courts, ex: ["Artiste","2026","NOMADE"]
  "bottomCopy": "string",    // 2 lignes du bas séparées par \\n
  "ctaLabel": "string",      // ex: "/ nomadeclan.com"
  "ctaUrl": "nomadeclan.com"
}`;

  const response = await callClaudeAPI(systemPrompt, apiKey);
  return extractJSON(response);
}

// ── Main App ───────────────────────────────────────────────────────────────
function App() {
  const [templateId, setTemplateId] = useState(window.TEMPLATES[0].id);
  const [data, setData] = useState({
    ...window.TEMPLATES[0].defaults,
    photoUrl: '',
    photoPosition: '50% 30%',
  });
  const [aiPrompt, setAiPrompt] = useState('');
  const [aiLoading, setAiLoading] = useState(false);
  const [aiError, setAiError] = useState('');
  const [apiKey, setApiKey] = useState(() => localStorage.getItem('nomade_anthropic_key') || '');
  const [showKey, setShowKey] = useState(false);
  const [previewMode, setPreviewMode] = useState('post');
  const [downloadingPost, setDownloadingPost] = useState(false);
  const [downloadingStory, setDownloadingStory] = useState(false);
  const [leftTab, setLeftTab] = useState('edit');

  const postRef = useRef(null);
  const storyRef = useRef(null);
  const previewWrapRef = useRef(null);
  const [previewScale, setPreviewScale] = useState({ post: 0.5, story: 0.4 });

  // Auto-fit the preview to the available space (mobile + desktop)
  useEffect(() => {
    const el = previewWrapRef.current;
    if (!el) return;
    const compute = () => {
      const w = el.clientWidth;
      const h = el.clientHeight || window.innerHeight;
      if (w <= 0) return;
      const postS = Math.min(0.5, w / 1080, h / 1350);
      const storyS = Math.min(0.4, w / 1080, h / 1920);
      setPreviewScale({
        post: postS > 0.04 ? postS : 0.5,
        story: storyS > 0.04 ? storyS : 0.4,
      });
    };
    compute();
    const ro = new ResizeObserver(compute);
    ro.observe(el);
    window.addEventListener('resize', compute);
    return () => { ro.disconnect(); window.removeEventListener('resize', compute); };
  }, []);

  const applyTemplate = (id) => {
    const tpl = window.TEMPLATES.find(t => t.id === id);
    if (!tpl) return;
    setTemplateId(id);
    setData(prev => ({ ...tpl.defaults, photoUrl: prev.photoUrl, photoPosition: prev.photoPosition }));
  };

  const resetTemplate = (id) => {
    const tpl = window.TEMPLATES.find(t => t.id === id);
    if (!tpl) return;
    setTemplateId(id);
    setData({ ...tpl.defaults, photoUrl: '', photoPosition: '50% 30%' });
  };

  const isCertif = data.layout === 'certif';
  const isSession = data.layout === 'session';
  const isPromo = data.layout === 'promo';

  const update = (key) => (e) => {
    const v = e.target ? e.target.value : e;
    setData(prev => ({ ...prev, [key]: v }));
  };

  const updateChip = (idx) => (e) => {
    const v = e.target.value;
    setData(prev => {
      const chips = [...prev.chips];
      chips[idx] = v;
      return { ...prev, chips };
    });
  };

  const onPhotoFile = (file) => {
    if (!file) return;
    const reader = new FileReader();
    reader.onload = () => setData(prev => ({ ...prev, photoUrl: reader.result }));
    reader.readAsDataURL(file);
  };

  const photoDropProps = {
    onDragOver: (e) => { e.preventDefault(); },
    onDrop: (e) => {
      e.preventDefault();
      const file = e.dataTransfer.files?.[0];
      if (file && file.type.startsWith('image/')) onPhotoFile(file);
    },
  };

  const runAI = async () => {
    if (!aiPrompt.trim()) { setAiError('Décris ce que tu veux annoncer.'); return; }
    if (!apiKey.trim()) { setAiError('Colle ta clé API Anthropic dans le champ ci-dessus.'); return; }
    setAiLoading(true);
    setAiError('');
    try {
      const result = await generateWithAI(aiPrompt, templateId, apiKey.trim());
      setData(prev => ({ ...prev, ...result }));
    } catch (e) {
      console.error(e);
      if (e.message === 'INVALID_KEY') setAiError('Clé API invalide ou expirée.');
      else if (e.message === 'NO_KEY') setAiError('Pas de clé API.');
      else if (e.message?.startsWith('API ')) setAiError(e.message);
      else setAiError('Erreur IA — vérifie ta connexion ou réessaie.');
    }
    setAiLoading(false);
  };

  const updateApiKey = (v) => {
    setApiKey(v);
    if (v.trim()) localStorage.setItem('nomade_anthropic_key', v.trim());
    else localStorage.removeItem('nomade_anthropic_key');
  };

  const downloadPng = async (kind) => {
    const node = kind === 'post' ? postRef.current : storyRef.current;
    if (!node) return;
    const setLoading = kind === 'post' ? setDownloadingPost : setDownloadingStory;
    setLoading(true);
    try {
      const blob = await window.htmlToImage.toBlob(node, {
        pixelRatio: 1,
        width: 1080,
        height: kind === 'post' ? 1350 : 1920,
        backgroundColor: '#060606',
      });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      const slug = (data.headline || data.artistName || 'nomade').toLowerCase()
        .normalize('NFD').replace(/[\u0300-\u036f]/g, '')
        .replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '') || 'post';
      a.download = `nomade-${slug}-${kind === 'post' ? '1080x1350' : '1080x1920'}.png`;
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      setTimeout(() => URL.revokeObjectURL(url), 1000);
    } catch (e) {
      console.error(e);
      alert('Erreur lors de la génération : ' + e.message);
    }
    setLoading(false);
  };

  return (
    <div className="app-root" style={{
      width: '100vw', minHeight: '100vh',
      background: '#0C0A08',
      color: '#ECE3D4',
      display: 'grid',
      gridTemplateColumns: 'minmax(420px, 460px) 1fr',
    }}>

      {/* ── LEFT: Form ── */}
      <aside className="app-aside" style={{
        background: 'linear-gradient(180deg, #16120D 0%, #070605 100%)',
        borderRight: '1px solid rgba(236,227,212,0.08)',
        padding: '32px 28px',
        height: '100vh',
        overflowY: 'auto',
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 24 }}>
          <img src="assets/nomade-logo.png" style={{ height: 40, width: 'auto', filter: 'drop-shadow(0 0 12px rgba(193,106,67,0.5))' }} />
          <div>
            <div style={{ fontFamily: 'Space Grotesk', fontWeight: 700, fontSize: 16, letterSpacing: '0.4em', color: '#ECE3D4' }}>
              NOMADE
            </div>
            <div style={{ fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.3em', color: 'rgba(236,227,212,0.45)', textTransform: 'uppercase', marginTop: 2 }}>
              / Générateur de posts
            </div>
          </div>
        </div>

        {/* Left-panel tabs */}
        <div style={{
          display: 'flex', gap: 6, marginBottom: 22,
          background: 'rgba(236,227,212,0.04)',
          padding: 5,
          borderRadius: 10,
        }}>
          {[
            { id: 'edit', label: 'Édition' },
            { id: 'import', label: 'Import URL' },
          ].map(t => (
            <button key={t.id}
              onClick={() => setLeftTab(t.id)}
              style={{
                flex: 1,
                padding: '10px 12px',
                background: leftTab === t.id ? 'rgba(193,106,67,0.3)' : 'transparent',
                border: 'none',
                borderRadius: 7,
                color: leftTab === t.id ? '#ECE3D4' : 'rgba(236,227,212,0.55)',
                fontFamily: 'Space Grotesk', fontWeight: 600, fontSize: 12,
                letterSpacing: '0.14em', textTransform: 'uppercase',
                cursor: 'pointer',
                transition: 'all 150ms',
              }}>
              {t.label}
            </button>
          ))}
        </div>

        {leftTab === 'import' ? (
          <ImportTab onPickImage={(dataUrl) => {
            setData(prev => ({ ...prev, photoUrl: dataUrl }));
            setLeftTab('edit');
          }} />
        ) : (<></>)}

        {leftTab === 'edit' && (<>
        {/* Templates */}
        <Field label="— Type de post">
          <TemplatePicker value={templateId} onChange={applyTemplate} />
          <button
            onClick={() => resetTemplate(templateId)}
            style={{
              width: '100%', marginTop: 10,
              padding: '10px 14px',
              background: 'rgba(236,227,212,0.04)',
              border: '1px solid rgba(236,227,212,0.12)',
              borderRadius: 8,
              color: 'rgba(236,227,212,0.7)',
              fontFamily: 'JetBrains Mono', fontWeight: 500, fontSize: 11,
              letterSpacing: '0.22em', textTransform: 'uppercase',
              cursor: 'pointer',
              display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
              transition: 'all 150ms',
            }}
            onMouseEnter={e => {
              e.currentTarget.style.background = 'rgba(193,106,67,0.12)';
              e.currentTarget.style.borderColor = 'rgba(193,106,67,0.4)';
              e.currentTarget.style.color = '#ECE3D4';
            }}
            onMouseLeave={e => {
              e.currentTarget.style.background = 'rgba(236,227,212,0.04)';
              e.currentTarget.style.borderColor = 'rgba(236,227,212,0.12)';
              e.currentTarget.style.color = 'rgba(236,227,212,0.7)';
            }}>
            ↺  Reset le template
          </button>
        </Field>

        {/* AI */}
        <div style={{
          margin: '24px 0',
          padding: 16,
          background: 'linear-gradient(135deg, rgba(142,69,39,0.20) 0%, rgba(193,106,67,0.14) 50%, rgba(213,138,98,0.12) 100%)',
          border: '1px solid rgba(193,106,67,0.35)',
          borderRadius: 12,
        }}>
          <div style={{
            fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.3em',
            color: '#CFBFA4', textTransform: 'uppercase', marginBottom: 10, fontWeight: 600,
          }}>✦ Génération IA</div>

          <div style={{ marginBottom: 10 }}>
            <div style={{
              display: 'flex', alignItems: 'center', justifyContent: 'space-between',
              fontFamily: 'JetBrains Mono', fontSize: 9, letterSpacing: '0.24em',
              color: 'rgba(236,227,212,0.45)', textTransform: 'uppercase', marginBottom: 4,
            }}>
              <span>Clé API Anthropic</span>
              <button onClick={() => setShowKey(s => !s)}
                style={{
                  background: 'transparent', border: 'none', color: '#CFBFA4',
                  cursor: 'pointer', fontFamily: 'inherit', fontSize: 9, letterSpacing: '0.24em',
                }}>{showKey ? 'masquer' : 'afficher'}</button>
            </div>
            <input
              type={showKey ? 'text' : 'password'}
              value={apiKey}
              onChange={e => updateApiKey(e.target.value)}
              placeholder="sk-ant-..."
              autoComplete="off"
              style={{
                width: '100%', padding: '8px 10px',
                background: 'rgba(0,0,0,0.35)',
                border: '1px solid rgba(236,227,212,0.1)',
                borderRadius: 6,
                color: '#ECE3D4', fontFamily: 'JetBrains Mono', fontSize: 11,
                outline: 'none',
              }}
            />
          </div>

          <Textarea
            placeholder="Ex: Davy rejoint NOMADE en tant qu'artiste. Rap français, EP1 à venir."
            value={aiPrompt}
            onChange={e => setAiPrompt(e.target.value)}
            style={{ minHeight: 70, fontSize: 13, background: 'rgba(0,0,0,0.25)' }}
          />
          <button
            onClick={runAI}
            disabled={aiLoading}
            style={{
              width: '100%', marginTop: 10,
              padding: '12px 18px',
              background: aiLoading
                ? 'rgba(193,106,67,0.4)'
                : 'linear-gradient(135deg, #8E4527 0%, #C16A43 70%, #D58A62 110%)',
              border: 'none', borderRadius: 8,
              color: '#0C0A08',
              fontFamily: 'Space Grotesk', fontWeight: 700, fontSize: 13,
              letterSpacing: '0.16em', textTransform: 'uppercase',
              cursor: aiLoading ? 'wait' : 'pointer',
              boxShadow: '0 6px 20px rgba(193,106,67,0.3)',
            }}>
            {aiLoading ? '⟳ Génération…' : '✦  Générer le contenu'}
          </button>
          {aiError && <div style={{ marginTop: 8, fontSize: 12, color: '#ff9c8c' }}>{aiError}</div>}
        </div>

        {/* Photo */}
        <Field label="— Photo">
          <div {...photoDropProps}
            style={{
              border: '1px dashed rgba(193,106,67,0.4)',
              borderRadius: 10,
              padding: 14,
              background: 'rgba(193,106,67,0.05)',
              textAlign: 'center',
              cursor: 'pointer',
              position: 'relative',
              overflow: 'hidden',
              minHeight: 90,
              display: 'flex', alignItems: 'center', justifyContent: 'center',
            }}
            onClick={() => document.getElementById('photo-input').click()}>
            <input id="photo-input" type="file" accept="image/*"
              style={{ display: 'none' }}
              onChange={(e) => onPhotoFile(e.target.files?.[0])} />
            {data.photoUrl ? (
              <>
                <img src={data.photoUrl}
                  style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover', opacity: 0.5 }} />
                <div style={{ position: 'relative', fontFamily: 'JetBrains Mono', fontSize: 11, letterSpacing: '0.22em', textTransform: 'uppercase', color: '#ECE3D4', background: 'rgba(6,6,6,0.7)', padding: '6px 12px', borderRadius: 4 }}>
                  ✓ Photo chargée — clique pour changer
                </div>
              </>
            ) : (
              <div style={{ fontSize: 13, color: 'rgba(236,227,212,0.6)' }}>
                <div style={{ fontFamily: 'Space Grotesk', fontWeight: 600, color: '#CFBFA4', marginBottom: 4 }}>Glisse une photo ici</div>
                <div style={{ fontSize: 11, color: 'rgba(236,227,212,0.4)' }}>ou click pour parcourir</div>
              </div>
            )}
          </div>
        </Field>

        {data.photoUrl && (
          <Field label="— Cadrage photo (Y)" hint="Plus bas = on voit plus le haut de la photo (visage)">
            <input type="range" min="0" max="100" step="5"
              value={parseInt(data.photoPosition.split(' ')[1])}
              onChange={(e) => setData(prev => ({ ...prev, photoPosition: `50% ${e.target.value}%` }))}
              style={{ width: '100%', accentColor: '#C16A43' }} />
          </Field>
        )}

        {/* Pill */}
        <Field label="— Pastille top-droite">
          <Input value={data.pill} onChange={update('pill')} />
        </Field>

        {/* Kicker */}
        <Field label="— Kicker (étiquette mono)">
          <Input value={data.kicker} onChange={update('kicker')} />
        </Field>

        {isCertif ? (
          <>
            <Field label="— Format de certification">
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 6 }}>
                {[
                  { id: 'album', label: 'Album', sub: 'Ventes' },
                  { id: 'single', label: 'Single', sub: 'Streams' },
                ].map(f => {
                  const active = (data.certifFormat || 'album') === f.id;
                  return (
                    <button key={f.id}
                      onClick={() => {
                        const defaults = f.id === 'album'
                          ? { certifType: 'OR', salesNumber: '50.000' }
                          : { certifType: 'OR', salesNumber: '15.000.000' };
                        setData(prev => ({ ...prev, certifFormat: f.id, ...defaults }));
                      }}
                      style={{
                        background: active ? 'rgba(193,106,67,0.2)' : 'rgba(236,227,212,0.04)',
                        border: `1px solid ${active ? 'rgba(193,106,67,0.6)' : 'rgba(236,227,212,0.12)'}`,
                        borderRadius: 8,
                        color: active ? '#ECE3D4' : 'rgba(236,227,212,0.7)',
                        cursor: 'pointer',
                        transition: 'all 150ms',
                        textAlign: 'left',
                        padding: 12,
                      }}>
                      <div style={{
                        fontFamily: 'Space Grotesk', fontWeight: 700, fontSize: 14,
                        letterSpacing: '0.12em', textTransform: 'uppercase',
                      }}>{f.label}</div>
                      <div style={{
                        fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.18em',
                        color: active ? '#CFBFA4' : 'rgba(236,227,212,0.4)',
                        marginTop: 4, textTransform: 'uppercase',
                      }}>{f.sub}</div>
                    </button>
                  );
                })}
              </div>
            </Field>

            <Field label="— Type de certification">
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 6 }}>
                {(() => {
                  const albumTypes = [
                    { id: 'OR', label: 'Or', sales: '50.000', color: '#f4c430' },
                    { id: 'PLATINE', label: 'Platine', sales: '100.000', color: '#e8e8e8' },
                    { id: '2PLATINE', label: '×2 Platine', sales: '200.000', color: '#e8e8e8' },
                    { id: '3PLATINE', label: '×3 Platine', sales: '300.000', color: '#e8e8e8' },
                    { id: 'DIAMANT', label: 'Diamant', sales: '500.000', color: '#7dd3fc' },
                    { id: '2DIAMANT', label: '×2 Diamant', sales: '1.000.000', color: '#7dd3fc' },
                  ];
                  const singleTypes = [
                    { id: 'OR', label: 'Single Or', sales: '15.000.000', color: '#f4c430' },
                    { id: 'PLATINE', label: 'Single Platine', sales: '30.000.000', color: '#e8e8e8' },
                    { id: 'DIAMANT', label: 'Single Diamant', sales: '50.000.000', color: '#7dd3fc' },
                    { id: '2DIAMANT', label: '×2 Diamant', sales: '100.000.000', color: '#7dd3fc' },
                  ];
                  const types = (data.certifFormat || 'album') === 'single' ? singleTypes : albumTypes;
                  return types.map(t => {
                    const active = data.certifType === t.id;
                    return (
                      <button key={t.id}
                        onClick={() => setData(prev => ({ ...prev, certifType: t.id, salesNumber: t.sales }))}
                        style={{
                          padding: '12px 8px',
                          background: active ? `${t.color}33` : 'rgba(236,227,212,0.04)',
                          border: `1px solid ${active ? t.color : 'rgba(236,227,212,0.12)'}`,
                          borderRadius: 8,
                          color: active ? t.color : 'rgba(236,227,212,0.75)',
                          fontFamily: 'Space Grotesk', fontWeight: 600,
                          fontSize: 12, letterSpacing: '0.14em', textTransform: 'uppercase',
                          cursor: 'pointer', transition: 'all 150ms',
                        }}>
                        {t.label}
                      </button>
                    );
                  });
                })()}
              </div>
            </Field>

            <Field label="— Nom de l'artiste / groupe">
              <Input value={data.artistName || ''} onChange={update('artistName')} placeholder="ARTISTE" />
            </Field>

            <Field label="— Nom de l'album / single">
              <Input value={data.albumName || ''} onChange={update('albumName')} placeholder="Titre" />
            </Field>

            <Field label={data.certifFormat === 'single' ? "— Nombre de streams" : "— Nombre de ventes"}
              hint={data.certifFormat === 'single' ? "Ex: 15.000.000, 50.000.000" : "Ex: 50.000, 100.000, 500.000"}>
              <Input value={data.salesNumber || ''} onChange={update('salesNumber')}
                placeholder={data.certifFormat === 'single' ? '15.000.000' : '50.000'} />
            </Field>
          </>
        ) : isSession ? (
          <>
            <Field label="— Nom de l'artiste">
              <Input value={data.artistName || ''} onChange={update('artistName')} placeholder="ARTISTE" />
            </Field>
            <Field label="— Sous-titre italique">
              <Input value={data.subtitle} onChange={update('subtitle')} />
            </Field>
            <Field label="— Date de session" hint="Affichée à côté de REC ●">
              <Input value={data.sessionDate || ''} onChange={update('sessionDate')} placeholder="AUJOURD'HUI" />
            </Field>
            <Field label="— Chips (3 tags)">
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 6 }}>
                {[0,1,2].map(i => (
                  <Input key={i} value={data.chips[i] || ''} onChange={updateChip(i)} placeholder={`Tag ${i+1}`} />
                ))}
              </div>
            </Field>
          </>
        ) : (
          <>
            {templateId === 'signature' && (
              <Field label="— Type de signature">
                <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 6 }}>
                  {[
                    { id: 'artiste', label: 'Artiste', chip: 'Artiste', kicker: '/ NOUVELLE SIGNATURE · ARTISTE' },
                    { id: 'compositeur', label: 'Compositeur', chip: 'Compositeur', kicker: '/ NOUVELLE SIGNATURE · COMPOSITEUR' },
                  ].map(r => {
                    const active = (data.signatureRole || 'artiste') === r.id;
                    return (
                      <button key={r.id}
                        onClick={() => {
                          setData(prev => {
                            const chips = [...(prev.chips || ['','',''])];
                            chips[0] = r.chip;
                            return { ...prev, signatureRole: r.id, kicker: r.kicker, chips };
                          });
                        }}
                        style={{
                          padding: 12, textAlign: 'left',
                          background: active ? 'rgba(193,106,67,0.2)' : 'rgba(236,227,212,0.04)',
                          border: `1px solid ${active ? 'rgba(193,106,67,0.6)' : 'rgba(236,227,212,0.12)'}`,
                          borderRadius: 8,
                          color: active ? '#ECE3D4' : 'rgba(236,227,212,0.7)',
                          cursor: 'pointer',
                          transition: 'all 150ms',
                          fontFamily: 'Space Grotesk', fontWeight: 700, fontSize: 14,
                          letterSpacing: '0.12em', textTransform: 'uppercase',
                        }}>
                        {r.label}
                      </button>
                    );
                  })}
                </div>
              </Field>
            )}

            <Field label="— Headline (post)">
              <Input value={data.headline} onChange={update('headline')} />
            </Field>

            <Field label="— Sous-titre italique (post)">
              <Input value={data.subtitle} onChange={update('subtitle')} />
            </Field>

            <Field label="— Story · ligne 1">
              <Input value={data.storyTop} onChange={update('storyTop')} />
            </Field>
            <Field label="— Story · ligne 2 (italique)">
              <Input value={data.storyBottom} onChange={update('storyBottom')} />
            </Field>

            <Field label="— Chips (3 tags)">
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 6 }}>
                {[0,1,2].map(i => (
                  <Input key={i} value={data.chips[i] || ''} onChange={updateChip(i)} placeholder={`Tag ${i+1}`} />
                ))}
              </div>
            </Field>

            <Field label="— Compositeur (optionnel)" hint="Affiché en petit sur le post — laisse vide pour ne pas l'afficher">
              <Input value={data.composer || ''} onChange={update('composer')} placeholder="ex: Composé par Silly Raiito" />
            </Field>
          </>
        )}

        {/* Bottom copy */}
        <Field label="— Texte bas (post)">
          <Textarea value={data.bottomCopy} onChange={update('bottomCopy')} rows={3} />
        </Field>

        {/* CTA */}
        <Field label="— CTA label (story)">
          <Input value={data.ctaLabel} onChange={update('ctaLabel')} />
        </Field>
        <Field label="— URL">
          <Input value={data.ctaUrl} onChange={update('ctaUrl')} />
        </Field>

        </>)}
        <div style={{ height: 40 }} />
      </aside>

      {/* ── RIGHT: Preview + Download ── */}
      <main className="app-main" style={{
        padding: '32px 40px',
        height: '100vh',
        overflowY: 'auto',
        display: 'flex', flexDirection: 'column',
      }}>
        <div style={{
          display: 'flex', gap: 8, marginBottom: 24,
          background: 'rgba(236,227,212,0.04)',
          padding: 6,
          borderRadius: 12,
          width: 'fit-content',
        }}>
          {['post', 'story'].map(m => (
            <button key={m}
              onClick={() => setPreviewMode(m)}
              style={{
                padding: '10px 22px',
                background: previewMode === m ? 'rgba(193,106,67,0.3)' : 'transparent',
                border: 'none',
                borderRadius: 8,
                color: previewMode === m ? '#ECE3D4' : 'rgba(236,227,212,0.55)',
                fontFamily: 'Space Grotesk', fontWeight: 600, fontSize: 13,
                letterSpacing: '0.14em', textTransform: 'uppercase',
                cursor: 'pointer',
                transition: 'all 150ms',
              }}>
              {m === 'post' ? 'Post · 4:5' : 'Story · 9:16'}
            </button>
          ))}
        </div>

        <div ref={previewWrapRef} style={{
          flex: 1,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          gap: 32,
          padding: '0 0 24px',
          minHeight: 360,
        }}>
          <div style={{
            position: 'relative',
            transformOrigin: 'top center',
            background: '#000',
            borderRadius: 12,
            overflow: 'hidden',
            boxShadow: '0 30px 80px rgba(0,0,0,0.5), 0 0 60px rgba(193,106,67,0.14)',
          }}>
            {previewMode === 'post' ? (
              <div style={{
                width: 1080, height: 1350,
                transform: `scale(${previewScale.post})`, transformOrigin: 'top left',
                marginRight: 1080 * -(1 - previewScale.post), marginBottom: 1350 * -(1 - previewScale.post),
              }}>
                {isCertif ? <window.CertifPost data={data} />
                  : isSession ? <window.SessionPost data={data} />
                  : isPromo ? <window.PromoPost data={data} />
                  : <window.PostFlyer data={data} />}
              </div>
            ) : (
              <div style={{
                width: 1080, height: 1920,
                transform: `scale(${previewScale.story})`, transformOrigin: 'top left',
                marginRight: 1080 * -(1 - previewScale.story), marginBottom: 1920 * -(1 - previewScale.story),
              }}>
                {isCertif ? <window.CertifStory data={data} />
                  : isSession ? <window.SessionStory data={data} />
                  : isPromo ? <window.PromoStory data={data} />
                  : <window.StoryFlyer data={data} />}
              </div>
            )}
          </div>
        </div>

        {/* Hidden full-size mirrors used by the download function */}
        <div style={{ position: 'absolute', top: 0, left: -20000, pointerEvents: 'none' }}>
          <div ref={postRef}>
            {isCertif ? <window.CertifPost data={data} />
              : isSession ? <window.SessionPost data={data} />
              : isPromo ? <window.PromoPost data={data} />
              : <window.PostFlyer data={data} />}
          </div>
          <div ref={storyRef}>
            {isCertif ? <window.CertifStory data={data} />
              : isSession ? <window.SessionStory data={data} />
              : isPromo ? <window.PromoStory data={data} />
              : <window.StoryFlyer data={data} />}
          </div>
        </div>

        {/* Download bar */}
        <div style={{
          display: 'flex', gap: 12, alignItems: 'center', justifyContent: 'center',
          padding: '20px 24px',
          background: 'rgba(236,227,212,0.04)',
          borderRadius: 14,
          border: '1px solid rgba(236,227,212,0.08)',
        }}>
          <button onClick={() => downloadPng('post')} disabled={downloadingPost}
            style={{
              padding: '14px 26px',
              background: downloadingPost ? 'rgba(193,106,67,0.4)' : 'linear-gradient(135deg, #8E4527 0%, #C16A43 70%, #D58A62 110%)',
              border: 'none', borderRadius: 10, color: '#0C0A08',
              fontFamily: 'Space Grotesk', fontWeight: 700, fontSize: 14,
              letterSpacing: '0.14em', textTransform: 'uppercase',
              cursor: downloadingPost ? 'wait' : 'pointer',
              boxShadow: '0 8px 24px rgba(193,106,67,0.3)',
            }}>
            {downloadingPost ? '⟳ …' : '⬇  Post (1080×1350)'}
          </button>
          <button onClick={() => downloadPng('story')} disabled={downloadingStory}
            style={{
              padding: '14px 26px',
              background: downloadingStory ? 'rgba(193,106,67,0.4)' : 'linear-gradient(135deg, #8E4527 0%, #C16A43 70%, #D58A62 110%)',
              border: 'none', borderRadius: 10, color: '#0C0A08',
              fontFamily: 'Space Grotesk', fontWeight: 700, fontSize: 14,
              letterSpacing: '0.14em', textTransform: 'uppercase',
              cursor: downloadingStory ? 'wait' : 'pointer',
              boxShadow: '0 8px 24px rgba(193,106,67,0.3)',
            }}>
            {downloadingStory ? '⟳ …' : '⬇  Story (1080×1920)'}
          </button>
          <button onClick={async () => { await downloadPng('post'); await downloadPng('story'); }}
            disabled={downloadingPost || downloadingStory}
            style={{
              padding: '14px 26px',
              background: 'rgba(236,227,212,0.08)',
              border: '1px solid rgba(236,227,212,0.18)',
              borderRadius: 10, color: '#ECE3D4',
              fontFamily: 'Space Grotesk', fontWeight: 600, fontSize: 13,
              letterSpacing: '0.12em', textTransform: 'uppercase',
              cursor: 'pointer',
            }}>
            ⬇  Les deux
          </button>
        </div>
      </main>

    </div>
  );
}

function mount() {
  if (!window.PostFlyer || !window.StoryFlyer || !window.CertifPost || !window.CertifStory
      || !window.SessionPost || !window.SessionStory || !window.PromoPost || !window.PromoStory
      || !window.TEMPLATES || !window.htmlToImage) {
    return setTimeout(mount, 50);
  }
  const root = ReactDOM.createRoot(document.getElementById('root'));
  root.render(<App />);
}
mount();
