// useDB.jsx — React hook wrapping all disene IndexedDB CRUD via Dexie.
// Exports window.useDiseneDB.

const { useState: _db_us, useEffect: _db_ue, useRef: _db_ur } = React;

// ─── DB ↔ App model helpers ────────────────────────────────────────

function _fmtDate(iso) {
  if (!iso) return "recently";
  if (!iso.includes("T")) return iso; // already human-readable
  return iso.slice(0, 10);
}

async function _load(db, conceptRow) {
  const id = conceptRow.id;
  const [cons, fns, persp, pats, ess, linksOut] = await Promise.all([
    db.consists.where("concept_id").equals(id).toArray(),
    db.functions.where("concept_id").equals(id).toArray(),
    db.perspectives.where("concept_id").equals(id).toArray(),
    db.patterns.where("concept_id").equals(id).toArray(),
    db.essences.where("concept_id").equals(id).toArray(),
    db.links.where("concept_id_a").equals(id).toArray(),
  ]);

  return {
    id,
    title:    conceptRow.name      || "",
    category: conceptRow.category  || "—",
    updated:  _fmtDate(conceptRow.updated_at),
    consist:  cons[0]?.value        || "",
    function: fns[0]?.value         || "",
    perspectives: persp.map(p => ({
      id:        p.id,
      title:     p.use_for   || "",
      body:      p.for_what  || "",
      patternId: p.pattern_id || null,
    })),
    patterns: pats.map(p => ({
      id:        p.id,
      title:     p.name        || "",
      body:      p.description || "",
      essenceId: p.essence_id  || null,
    })),
    essences: ess.map(e => ({
      id:   e.id,
      body: e.description || "",
    })),
    links: linksOut.map(l => ({
      id:       l.id,
      targetId: l.concept_id_b,
      type:     l.link_type || "unknown",
    })),
  };
}

async function _persist(db, concept) {
  const now = new Date().toISOString();
  await db.transaction("rw", [
    db.concepts, db.consists, db.functions,
    db.perspectives, db.patterns, db.essences, db.links,
  ], async () => {
    await db.concepts.put({
      id:         concept.id,
      name:       concept.title    || "",
      category:   concept.category || "—",
      created_at: concept._created || now,
      updated_at: now,
    });

    await db.consists.where("concept_id").equals(concept.id).delete();
    if (concept.consist)
      await db.consists.put({ id: "cons_" + concept.id, concept_id: concept.id, value: concept.consist, updated_at: now });

    await db.functions.where("concept_id").equals(concept.id).delete();
    if (concept.function)
      await db.functions.put({ id: "func_" + concept.id, concept_id: concept.id, value: concept.function, updated_at: now });

    await db.perspectives.where("concept_id").equals(concept.id).delete();
    for (const p of (concept.perspectives || []))
      await db.perspectives.put({
        id: p.id, concept_id: concept.id,
        pattern_id: p.patternId || null,
        use_for:    p.title     || "",
        for_what:   p.body      || "",
        updated_at: now,
      });

    await db.patterns.where("concept_id").equals(concept.id).delete();
    for (const p of (concept.patterns || []))
      await db.patterns.put({
        id: p.id, concept_id: concept.id,
        essence_id:  p.essenceId || null,
        name:        p.title     || "",
        description: p.body      || "",
        updated_at:  now,
      });

    await db.essences.where("concept_id").equals(concept.id).delete();
    for (const e of (concept.essences || []))
      await db.essences.put({
        id: e.id, concept_id: concept.id,
        name:        "",
        description: e.body || "",
        updated_at:  now,
      });

    await db.links.where("concept_id_a").equals(concept.id).delete();
    for (const l of (concept.links || [])) {
      const targetId = typeof l === "string" ? l : l.targetId;
      const linkType = typeof l === "string" ? "unknown" : (l.type || "unknown");
      await db.links.put({
        id:           l.id || (concept.id + "_" + targetId),
        concept_id_a: concept.id,
        concept_id_b: targetId,
        link_type:    linkType,
        updated_at:   now,
      });
    }
  });
}

async function _deleteFromDB(db, id) {
  await db.transaction("rw", [
    db.concepts, db.consists, db.functions,
    db.perspectives, db.patterns, db.essences, db.links,
  ], async () => {
    await db.concepts.delete(id);
    await db.consists.where("concept_id").equals(id).delete();
    await db.functions.where("concept_id").equals(id).delete();
    await db.perspectives.where("concept_id").equals(id).delete();
    await db.patterns.where("concept_id").equals(id).delete();
    await db.essences.where("concept_id").equals(id).delete();
    await db.links.where("concept_id_a").equals(id).delete();
    await db.links.where("concept_id_b").equals(id).delete();
  });
}

// ─── Hook ──────────────────────────────────────────────────────────

function useDiseneDB() {
  const [concepts, setConcepts] = _db_us([]);
  const [loading, setLoading]   = _db_us(true);
  const [showUpgrade, setShowUpgrade] = _db_us(false);

  const latestRef    = _db_ur([]);     // always-current mirror of concepts state
  const debounceRef  = _db_ur({});     // debounce timers per concept id

  function _set(next) {
    const arr = typeof next === "function" ? next(latestRef.current) : next;
    latestRef.current = arr;
    setConcepts(arr);
  }

  async function _reload() {
    const db = window.db;
    try {
      const rows = await db.concepts.toArray();
      const assembled = await Promise.all(rows.map(r => _load(db, r)));
      _set(assembled);
    } catch (err) {
      console.error("diseneDB reload:", err);
    }
  }

  _db_ue(() => {
    async function init() {
      const db = window.db;
      try {
        const count = await db.concepts.count();
        if (count === 0 && window.SEED_CONCEPTS?.length) {
          for (const c of window.SEED_CONCEPTS)
            await _persist(db, { ...c, _created: new Date().toISOString() });
        }
        const rows = await db.concepts.toArray();
        const assembled = await Promise.all(rows.map(r => _load(db, r)));
        _set(assembled);
      } catch (err) {
        console.error("diseneDB init:", err);
        _set(window.SEED_CONCEPTS || []);
      } finally {
        setLoading(false);
      }
    }
    init();
  }, []);

  _db_ue(() => {
    window.addEventListener("disene:synced", _reload);
    return () => window.removeEventListener("disene:synced", _reload);
  }, []);

  async function createConcept(title) {
    const db = window.db;
    const count = await db.concepts.count();
    if (count >= 100) { setShowUpgrade(true); return null; }

    const id  = "c" + Date.now();
    const now = new Date().toISOString();
    const concept = {
      id, title, category: "—",
      consist: "", function: "",
      perspectives: [], patterns: [], essences: [], links: [],
      updated: "moments ago", _created: now,
    };
    await _persist(db, concept);
    _set(cs => [concept, ...cs]);
    return id;
  }

  async function updateConcept(id, patch) {
    const existing = latestRef.current.find(c => c.id === id);
    if (!existing) return;

    const updated = typeof patch === "function"
      ? patch(existing)
      : { ...existing, ...patch };
    updated.updated = "moments ago";

    _set(cs => cs.map(c => c.id === id ? updated : c));

    clearTimeout(debounceRef.current[id]);
    debounceRef.current[id] = setTimeout(async () => {
      try { await _persist(window.db, updated); }
      catch (err) { console.error("diseneDB persist:", err); }
    }, 600);
  }

  async function deleteConcept(id) {
    await _deleteFromDB(window.db, id);
    _set(cs => cs.filter(c => c.id !== id));
  }

  return {
    concepts, loading,
    createConcept, updateConcept, deleteConcept,
    showUpgrade, closeUpgrade: () => setShowUpgrade(false),
  };
}

window.useDiseneDB = useDiseneDB;
