// Store réactif côté client Apportoo (modèle monica-roadmap).
// Charge /api/bootstrap au démarrage et expose les collections du NOUVEAU
// modèle de données sous window.Store. Le mock window.APPORTOO (src/data.js)
// reste chargé en parallèle : l'UI existante continue de fonctionner pendant
// la migration écran par écran.

const Store = {
  state: {
    organisations: [],
    contacts: [],
    contact_roles: [],
    opportunities: [],
    opportunity_candidates: [],
    placements: [],
    commission_lines: [],
    contracts: [],
    profile_master: [],
    profile_experiences: [],
    profile_skills: [],
    competence_dossiers: [],
    platform_accounts: [],
    conversations: [],
    memories: [],
    validation_queue: [],
    enrichment_queue: [],
    events_inbox: [],
    sources: [],
    source_contents: [],
    post_drafts: [],
  },
  ready: false,
  loading: false,
  error: null,
  listeners: new Set(),

  subscribe(fn) { this.listeners.add(fn); return () => this.listeners.delete(fn); },
  emit() { for (const fn of this.listeners) fn(); },

  async bootstrap() {
    if (this.loading) return;
    this.loading = true;
    try {
      const res = await fetch('/api/bootstrap');
      if (!res.ok) throw new Error(`bootstrap failed: ${res.status}`);
      const data = await res.json();
      for (const k of Object.keys(this.state)) {
        if (Array.isArray(data[k])) this.state[k] = data[k];
      }
      this.ready = true;
      this.error = null;
    } catch (e) {
      this.error = e.message;
      console.error('[Store.bootstrap]', e);
    } finally {
      this.loading = false;
      this.emit();
    }
  },

  // Helpers de lecture transverses utiles aux écrans.
  rolesOf(contactId) {
    return this.state.contact_roles.filter((r) => r.contact_id === contactId).map((r) => r.role);
  },
  contactsByRole(role) {
    const ids = new Set(this.state.contact_roles.filter((r) => r.role === role).map((r) => r.contact_id));
    return this.state.contacts.filter((c) => ids.has(c.id));
  },
  candidatesFor(opportunityId) {
    return this.state.opportunity_candidates.filter((c) => c.opportunity_id === opportunityId);
  },
  commissionsFor(placementId) {
    return this.state.commission_lines.filter((cl) => cl.placement_id === placementId);
  },

  // ─── CRUD générique (optimiste-léger : refetch via state local) ─────────
  // resource = clé d'état (ex. 'opportunities'). path = segment URL REST.
  async create(resource, path, body) {
    const res = await fetch(`/api/${path}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body),
    });
    if (!res.ok) throw new Error(`create ${path} failed: ${res.status}`);
    const created = await res.json();
    this.state[resource] = [...this.state[resource], created];
    this.emit();
    return created;
  },
  async update(resource, path, id, patch) {
    const res = await fetch(`/api/${path}/${encodeURIComponent(id)}`, {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(patch),
    });
    if (!res.ok) throw new Error(`update ${path} failed: ${res.status}`);
    const updated = await res.json();
    this.state[resource] = this.state[resource].map((x) => (x.id === id ? updated : x));
    this.emit();
    return updated;
  },
  async remove(resource, path, id) {
    const before = this.state[resource];
    this.state[resource] = before.filter((x) => x.id !== id);
    this.emit();
    try {
      const res = await fetch(`/api/${path}/${encodeURIComponent(id)}`, { method: 'DELETE' });
      if (!res.ok && res.status !== 204) throw new Error(`delete ${path} failed: ${res.status}`);
    } catch (e) {
      this.state[resource] = before;
      this.emit();
      throw e;
    }
  },
};

// Démarrage : on charge le bootstrap dès que le script est évalué.
Store.bootstrap();

window.Store = Store;
