// mod_mes_missions.jsx — Module MES MISSIONS / auto-apport, branché sur window.Store.
// Migre l'écran me.jsx (mock window.APPORTOO) vers le modèle réel :
//   • profile_master   → titre, bio, dispo, stack (1 ligne logique)
//   • profile_skills    → compétences catégorisées (category + items csv)
//   • profile_experiences → client, role, period, context, stack, achievements, results
//   • competence_dossiers → N dossiers dérivés par besoin/opportunité (name, opp, notes)
// Lecture : window.Store.state. Écriture : window.Store.create/update/remove
//   → PATCH/POST /api/profile_master|profile_skills|profile_experiences|competence_dossiers.
// Upload PDF du dossier = hors V1 (placeholder « upload à venir »), CRUD des métadonnées OK.
// Le mock (window.MeView défini dans me.jsx) reste intact : ce fichier est chargé APRÈS
// me.jsx dans index.html et redéfinit window.MeView. Style aligné mod_contacts / styles.css. FR.

// ─── Helpers ───────────────────────────────────────────────────────────────────
const mmSplit = (csv) => (csv || '').split(',').map((s) => s.trim()).filter(Boolean);
const mmJoin = (arr) => (arr || []).map((s) => s.trim()).filter(Boolean).join(', ');
// achievements / results sont stockés en csv ou json — on tolère les deux en lecture.
const mmLines = (val) => {
  if (val == null || val === '') return [];
  if (Array.isArray(val)) return val.map(String).map((s) => s.trim()).filter(Boolean);
  if (typeof val === 'string') {
    const t = val.trim();
    if (t.startsWith('[')) {
      try { const a = JSON.parse(t); if (Array.isArray(a)) return a.map(String).map((s) => s.trim()).filter(Boolean); } catch (e) { /* fallthrough */ }
    }
    // une réalisation par ligne (ou à défaut séparées par « ; »)
    return t.split(/\n|;/).map((s) => s.trim()).filter(Boolean);
  }
  return [];
};
// (ré)sérialise une liste de lignes en csv « ; » pour rester lisible côté D1.
const mmPackLines = (text) => mmLines(text).join(' ; ');

// Hook : ré-render quand le Store change (même pattern que mod_contacts.jsx).
function useMissionsSnapshot() {
  const [, force] = React.useReducer((x) => x + 1, 0);
  React.useEffect(() => window.Store.subscribe(force), []);
  return window.Store.state;
}

// Petit champ éditable inline (clic sur le crayon → input/textarea → save au blur/Entrée).
function InlineField({ label, value, onSave, multiline = false, placeholder = '—', mono = false }) {
  const [editing, setEditing] = React.useState(false);
  const [draft, setDraft] = React.useState(value || '');
  React.useEffect(() => { setDraft(value || ''); }, [value]);

  const commit = () => {
    setEditing(false);
    if ((draft || '') !== (value || '')) onSave(draft);
  };

  if (editing) {
    return (
      <div className="contact-field">
        {label && <span className="contact-field-k">{label}</span>}
        {multiline ? (
          <textarea
            className="contact-input"
            rows={4}
            autoFocus
            value={draft}
            onChange={(e) => setDraft(e.target.value)}
            onBlur={commit}
          />
        ) : (
          <input
            className="contact-input"
            autoFocus
            value={draft}
            onChange={(e) => setDraft(e.target.value)}
            onBlur={commit}
            onKeyDown={(e) => { if (e.key === 'Enter') commit(); if (e.key === 'Escape') setEditing(false); }}
          />
        )}
      </div>
    );
  }

  return (
    <div className="contact-field">
      {label && <span className="contact-field-k">{label}</span>}
      <div
        className={`mm-inline-view ${mono ? 'mono' : ''}`}
        onClick={() => setEditing(true)}
        title="Cliquer pour éditer"
      >
        <span style={value ? null : { color: 'var(--ink-4)' }}>{value || placeholder}</span>
        <window.Icon.edit size={12} className="mm-inline-pen" />
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────
// Vue principale
// ─────────────────────────────────────────────────────────────────
function MeView({ onToast }) {
  const state = useMissionsSnapshot();
  const toast = (m) => { if (onToast) onToast(m); };

  if (!window.Store.ready && !state.profile_master.length) {
    return <div className="page"><div className="empty">Chargement du profil…</div></div>;
  }

  const master = (state.profile_master || [])[0] || null;
  const skills = [...(state.profile_skills || [])].sort((a, b) => (a.position || 0) - (b.position || 0));
  const experiences = [...(state.profile_experiences || [])].sort((a, b) => (a.position || 0) - (b.position || 0));
  const dossiers = [...(state.competence_dossiers || [])].sort(
    (a, b) => String(b.created_at || '').localeCompare(String(a.created_at || ''))
  );

  const patchMaster = async (patch) => {
    if (!master) return;
    try {
      await window.Store.update('profile_master', 'profile_master', master.id, {
        ...patch, updated_at: new Date().toISOString().slice(0, 19).replace('T', ' '),
      });
      toast('Profil mis à jour ✓');
    } catch (e) { toast('Erreur : ' + e.message); }
  };

  return (
    <div className="page mm-page">
      <ProfileCard master={master} onPatch={patchMaster} />
      <SkillsCard skills={skills} onToast={toast} />
      <ExperiencesCard experiences={experiences} onToast={toast} />
      <DossiersCard dossiers={dossiers} state={state} onToast={toast} />
    </div>
  );
}

// ─── Profil maître ───────────────────────────────────────────────────────────
const DISPO_OPTIONS = [
  { value: 'open remote', label: 'Ouvert · remote' },
  { value: 'open onsite', label: 'Ouvert · sur site' },
  { value: 'open hybrid', label: 'Ouvert · hybride' },
  { value: 'busy', label: 'En mission' },
  { value: 'closed', label: 'Indisponible' },
];

function ProfileCard({ master, onPatch }) {
  if (!master) {
    return (
      <div className="card">
        <div className="card-head"><h2>Profil maître</h2></div>
        <div className="card-body"><div className="empty">Aucun profil maître. Le seed initialise normalement une ligne.</div></div>
      </div>
    );
  }
  const stack = mmSplit(master.stack);
  return (
    <div className="card">
      <div className="card-head">
        <h2>Profil maître</h2>
        <div className="grow" />
        <span className="contact-field-k">Disponibilité</span>
        <select
          className="contact-input"
          style={{ width: 'auto' }}
          value={master.dispo_status || ''}
          onChange={(e) => onPatch({ dispo_status: e.target.value })}
        >
          <option value="">—</option>
          {DISPO_OPTIONS.map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}
        </select>
      </div>
      <div className="card-body vstack" style={{ gap: 14 }}>
        <InlineField label="Titre / headline" value={master.titre} onSave={(v) => onPatch({ titre: v })} placeholder="Titre du profil" />
        <InlineField label="Bio" value={master.bio} onSave={(v) => onPatch({ bio: v })} multiline placeholder="Quelques lignes de présentation" />
        <div className="contact-field">
          <span className="contact-field-k">Stack (séparée par des virgules)</span>
          <div className="mm-tags">
            {stack.length
              ? stack.map((s) => <span key={s} className="tag turq">{s}</span>)
              : <span className="muted tiny">Aucune techno</span>}
          </div>
          <InlineField value={master.stack} onSave={(v) => onPatch({ stack: mmJoin(mmSplit(v)) })} mono placeholder="python, spark, dbt…" />
        </div>
      </div>
    </div>
  );
}

// ─── Compétences catégorisées (profile_skills) ────────────────────────────────
function SkillsCard({ skills, onToast }) {
  const [adding, setAdding] = React.useState(false);
  const [cat, setCat] = React.useState('');
  const [items, setItems] = React.useState('');

  const create = async () => {
    if (!cat.trim()) { onToast('Catégorie requise'); return; }
    try {
      await window.Store.create('profile_skills', 'profile_skills', {
        category: cat.trim(), items: mmJoin(mmSplit(items)),
        position: skills.length,
      });
      setCat(''); setItems(''); setAdding(false);
      onToast('Compétence ajoutée ✓');
    } catch (e) { onToast('Erreur : ' + e.message); }
  };

  return (
    <div className="card">
      <div className="card-head">
        <h2>Compétences</h2>
        <span className="count-pill">{skills.length}</span>
        <div className="grow" />
        <button className="btn" onClick={() => setAdding((a) => !a)}>
          <window.Icon.plus size={13} /> Catégorie
        </button>
      </div>
      <div className="card-body vstack" style={{ gap: 14 }}>
        {adding && (
          <div className="mm-add-row">
            <input className="contact-input" placeholder="Catégorie (ex. Cloud & infra)" value={cat} onChange={(e) => setCat(e.target.value)} autoFocus />
            <input className="contact-input" placeholder="Items séparés par des virgules" value={items} onChange={(e) => setItems(e.target.value)} />
            <button className="btn primary" onClick={create}>Ajouter</button>
            <button className="btn ghost" onClick={() => setAdding(false)}>Annuler</button>
          </div>
        )}
        {skills.length === 0 && !adding && <div className="empty">Aucune compétence catégorisée.</div>}
        {skills.map((s) => <SkillRow key={s.id} skill={s} onToast={onToast} />)}
      </div>
    </div>
  );
}

function SkillRow({ skill, onToast }) {
  const items = mmSplit(skill.items);
  const patch = async (p) => {
    try { await window.Store.update('profile_skills', 'profile_skills', skill.id, p); onToast('Compétence mise à jour ✓'); }
    catch (e) { onToast('Erreur : ' + e.message); }
  };
  const del = async () => {
    if (!window.confirm(`Supprimer la catégorie « ${skill.category} » ?`)) return;
    try { await window.Store.remove('profile_skills', 'profile_skills', skill.id); onToast('Catégorie supprimée'); }
    catch (e) { onToast('Erreur : ' + e.message); }
  };
  return (
    <div className="mm-skill-row">
      <div className="mm-skill-head">
        <div style={{ flex: 1, minWidth: 0 }}>
          <InlineField value={skill.category} onSave={(v) => v.trim() && patch({ category: v.trim() })} placeholder="Catégorie" />
        </div>
        <button className="btn ghost icon" onClick={del} title="Supprimer"><window.Icon.trash size={13} /></button>
      </div>
      <div className="mm-tags">
        {items.length
          ? items.map((it) => <span key={it} className="tag">{it}</span>)
          : <span className="muted tiny">Aucun item</span>}
      </div>
      <InlineField value={skill.items} onSave={(v) => patch({ items: mmJoin(mmSplit(v)) })} mono placeholder="items séparés par des virgules" />
    </div>
  );
}

// ─── Expériences (profile_experiences) ─────────────────────────────────────────
function ExperiencesCard({ experiences, onToast }) {
  const create = async () => {
    try {
      await window.Store.create('profile_experiences', 'profile_experiences', {
        role: '', client: 'Nouveau client', period: '', context: '', description: '',
        stack: '', achievements: '', results: '', position: experiences.length,
      });
      onToast('Expérience ajoutée ✓');
    } catch (e) { onToast('Erreur : ' + e.message); }
  };
  return (
    <div className="card">
      <div className="card-head">
        <h2>Expériences</h2>
        <span className="count-pill">{experiences.length}</span>
        <div className="grow" />
        <button className="btn" onClick={create}><window.Icon.plus size={13} /> Expérience</button>
      </div>
      <div className="card-body vstack" style={{ gap: 18 }}>
        {experiences.length === 0 && <div className="empty">Aucune expérience.</div>}
        {experiences.map((e) => <ExperienceRow key={e.id} exp={e} onToast={onToast} />)}
      </div>
    </div>
  );
}

function ExperienceRow({ exp, onToast }) {
  const stack = mmSplit(exp.stack);
  const achievements = mmLines(exp.achievements);
  const results = mmLines(exp.results);
  const patch = async (p) => {
    try { await window.Store.update('profile_experiences', 'profile_experiences', exp.id, p); onToast('Expérience mise à jour ✓'); }
    catch (err) { onToast('Erreur : ' + err.message); }
  };
  const del = async () => {
    if (!window.confirm('Supprimer cette expérience ?')) return;
    try { await window.Store.remove('profile_experiences', 'profile_experiences', exp.id); onToast('Expérience supprimée'); }
    catch (err) { onToast('Erreur : ' + err.message); }
  };
  return (
    <div className="mm-exp-row">
      <div className="mm-exp-head">
        <div className="contact-form-grid" style={{ flex: 1 }}>
          <InlineField label="Client" value={exp.client} onSave={(v) => patch({ client: v })} placeholder="Client final" />
          <InlineField label="Rôle" value={exp.role} onSave={(v) => patch({ role: v })} placeholder="Rôle / poste" />
          <InlineField label="Période" value={exp.period} onSave={(v) => patch({ period: v })} placeholder="ex. 2022 — auj." />
          <InlineField label="Stack" value={exp.stack} onSave={(v) => patch({ stack: mmJoin(mmSplit(v)) })} mono placeholder="techno1, techno2…" />
        </div>
        <button className="btn ghost icon" onClick={del} title="Supprimer"><window.Icon.trash size={13} /></button>
      </div>
      {stack.length > 0 && (
        <div className="mm-tags">{stack.map((s) => <span key={s} className="tag turq">{s}</span>)}</div>
      )}
      <InlineField label="Contexte" value={exp.context} onSave={(v) => patch({ context: v })} multiline placeholder="Contexte de la mission" />
      <div className="contact-field">
        <span className="contact-field-k">Réalisations (une par ligne)</span>
        {achievements.length > 0 && (
          <ul className="mm-bullets">{achievements.map((a, i) => <li key={i}>{a}</li>)}</ul>
        )}
        <InlineField value={mmLines(exp.achievements).join('\n')} onSave={(v) => patch({ achievements: mmPackLines(v) })} multiline placeholder="Une réalisation par ligne" />
      </div>
      <div className="contact-field">
        <span className="contact-field-k">Résultats chiffrés (une par ligne)</span>
        {results.length > 0 && (
          <ul className="mm-bullets mm-results">{results.map((r, i) => <li key={i}>{r}</li>)}</ul>
        )}
        <InlineField value={mmLines(exp.results).join('\n')} onSave={(v) => patch({ results: mmPackLines(v) })} multiline placeholder="ex. -40 % de latence, +3 M€ de CA…" />
      </div>
    </div>
  );
}

// ─── Dossiers de compétences (competence_dossiers) ─────────────────────────────
function DossiersCard({ dossiers, state, onToast }) {
  const [editing, setEditing] = React.useState(null); // dossier en cours d'édition ou {} pour création

  const oppById = React.useMemo(() => {
    const m = {};
    (state.opportunities || []).forEach((o) => { m[o.id] = o; });
    return m;
  }, [state.opportunities]);

  const del = async (d) => {
    if (!window.confirm(`Supprimer le dossier « ${d.name} » ?`)) return;
    try { await window.Store.remove('competence_dossiers', 'competence_dossiers', d.id); onToast('Dossier supprimé'); }
    catch (e) { onToast('Erreur : ' + e.message); }
  };

  return (
    <div className="card">
      <div className="card-head">
        <h2>Dossiers de compétences</h2>
        <span className="count-pill">{dossiers.length}</span>
        <div className="grow" />
        <button className="btn primary" onClick={() => setEditing({})}>
          <window.Icon.plus size={13} /> Nouveau dossier
        </button>
      </div>
      <div className="card-body vstack" style={{ gap: 12 }}>
        {dossiers.length === 0 && <div className="empty">Aucun dossier. Crée-en un par besoin / opportunité ciblée.</div>}
        {dossiers.map((d) => (
          <div key={d.id} className="mm-dossier-row">
            <window.Icon.file size={18} style={{ color: 'var(--brown)', flexShrink: 0 }} />
            <div style={{ flex: 1, minWidth: 0 }}>
              <div className="mm-dossier-name">{d.name}</div>
              <div className="hstack tiny muted" style={{ flexWrap: 'wrap', gap: 8 }}>
                {d.opportunity_id && oppById[d.opportunity_id]
                  ? <span><window.Icon.trending size={11} /> {oppById[d.opportunity_id].title}</span>
                  : <span className="muted">Aucune opportunité liée</span>}
                <span className={`tag ${d.r2_key ? 'turq' : ''}`}>
                  {d.r2_key ? 'PDF attaché' : 'upload à venir'}
                </span>
              </div>
              {d.notes && <div className="tiny" style={{ marginTop: 4 }}>{d.notes}</div>}
            </div>
            <button className="btn ghost icon" onClick={() => setEditing(d)} title="Éditer"><window.Icon.edit size={13} /></button>
            <button className="btn ghost icon" onClick={() => del(d)} title="Supprimer"><window.Icon.trash size={13} /></button>
          </div>
        ))}
      </div>
      {editing && (
        <DossierEditor
          dossier={editing.id ? editing : null}
          opportunities={state.opportunities || []}
          onClose={() => setEditing(null)}
          onToast={onToast}
        />
      )}
    </div>
  );
}

function DossierEditor({ dossier, opportunities, onClose, onToast }) {
  const [name, setName] = React.useState(dossier?.name || '');
  const [oppId, setOppId] = React.useState(dossier?.opportunity_id || '');
  const [notes, setNotes] = React.useState(dossier?.notes || '');
  const [saving, setSaving] = React.useState(false);

  React.useEffect(() => {
    const h = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', h);
    return () => window.removeEventListener('keydown', h);
  }, []);

  const save = async () => {
    if (!name.trim()) { onToast('Nom requis'); return; }
    setSaving(true);
    const body = { name: name.trim(), opportunity_id: oppId || null, notes: notes.trim() || null };
    try {
      if (dossier) {
        await window.Store.update('competence_dossiers', 'competence_dossiers', dossier.id, body);
        onToast('Dossier mis à jour ✓');
      } else {
        await window.Store.create('competence_dossiers', 'competence_dossiers', body);
        onToast('Dossier créé ✓');
      }
      onClose();
    } catch (e) { onToast('Erreur : ' + e.message); setSaving(false); }
  };

  const sortedOpps = [...opportunities].sort((a, b) => String(a.title).localeCompare(String(b.title)));

  return (
    <div className="opp-modal-overlay" onClick={onClose}>
      <div className="opp-modal" style={{ width: 'min(560px, 96vw)' }} onClick={(e) => e.stopPropagation()}>
        <div className="opp-modal-head">
          <window.Icon.file size={20} style={{ color: 'var(--brown)', marginTop: 2 }} />
          <h3 className="opp-modal-title">{dossier ? 'Éditer le dossier' : 'Nouveau dossier'}</h3>
          <div className="grow" />
          <button className="btn ghost icon" onClick={onClose}><window.Icon.x size={14} /></button>
        </div>
        <div className="card-body vstack" style={{ gap: 14, padding: 22 }}>
          <div className="contact-field">
            <span className="contact-field-k">Nom du dossier</span>
            <input className="contact-input" value={name} onChange={(e) => setName(e.target.value)} autoFocus placeholder="ex. Dossier Lead Data Eng — BNP CIB" />
          </div>
          <div className="contact-field">
            <span className="contact-field-k">Opportunité ciblée</span>
            <select className="contact-input" value={oppId} onChange={(e) => setOppId(e.target.value)}>
              <option value="">— Aucune —</option>
              {sortedOpps.map((o) => <option key={o.id} value={o.id}>{o.title}</option>)}
            </select>
          </div>
          <div className="contact-field">
            <span className="contact-field-k">Notes (angle, points à mettre en avant)</span>
            <textarea className="contact-input" rows={4} value={notes} onChange={(e) => setNotes(e.target.value)} />
          </div>
          <div className="hstack tiny muted" style={{ background: 'var(--bg-1)', padding: '8px 10px', borderRadius: 8 }}>
            <window.Icon.file size={13} />
            <span>Upload du PDF : à venir (V1.5). Les métadonnées sont gérées dès maintenant.</span>
          </div>
          <div className="hstack" style={{ justifyContent: 'flex-end', gap: 8 }}>
            <button className="btn ghost" onClick={onClose}>Annuler</button>
            <button className="btn primary" onClick={save} disabled={saving}>
              {dossier ? 'Enregistrer' : 'Créer'}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

window.MeView = MeView;
