/* ============================================================
 * Larspeenghar Pedigree — frontend data-access layer for the
 * scalable MySQL backend (api_db.php).
 *
 * When api_db.php is reachable, the app runs in "DB mode": the herd
 * register loads ONE PAGE of animals at a time (server-side search +
 * pagination + per-owner scoping), instead of pulling the whole herd
 * into the browser. This is what makes 3,000,000 animals possible.
 *
 * If api_db.php is NOT present, window.LpDB.active stays false and the
 * app keeps using its existing local / flat-file behaviour unchanged.
 * ============================================================ */
(function () {
  "use strict";
  const API = "api_db.php";

  async function call(url, opts) {
    const r = await fetch(url, Object.assign({ credentials: "same-origin" }, opts || {}));
    let body = null;
    try { body = await r.json(); } catch (e) {}
    if (!r.ok) {
      const err = new Error((body && body.error) || "HTTP " + r.status);
      err.status = r.status;
      throw err;
    }
    return body || {};
  }

  const LpDB = {
    active: false, // true once a real MySQL backend answers
    user: null,

    /* Probe api_db.php once. Only flips `active` if it returns JSON. */
    async probe() {
      try {
        const r = await fetch(API + "?action=session", { credentials: "same-origin" });
        const ct = (r.headers.get("content-type") || "").toLowerCase();
        if (!r.ok || !ct.includes("json")) { this.active = false; return false; }
        const b = await r.json();
        this.active = true;
        this.user = b.user || null;
        return true;
      } catch (e) {
        this.active = false;
        return false;
      }
    },

    async login(username, password) {
      const b = await call(API + "?action=login", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ username, password }),
      });
      this.user = b.user;
      return b.user;
    },

    async logout() {
      try { await call(API + "?action=logout", { method: "POST" }); } catch (e) {}
      this.user = null;
    },

    async session() {
      const b = await call(API + "?action=session");
      this.user = b.user || null;
      return this.user;
    },

    /* One page of animals. opts: {q, breed, sex, province, sf, page, perPage, sort}
       Returns {rows, total, page, pages, per_page}. */
    async animalsPage(opts) {
      opts = opts || {};
      const p = new URLSearchParams();
      p.set("action", "animals");
      p.set("page", opts.page || 1);
      p.set("per_page", opts.perPage || 50);
      if (opts.q) p.set("q", opts.q);
      if (opts.breed) p.set("breed", opts.breed);
      if (opts.sex) p.set("sex", opts.sex);
      if (opts.province) p.set("province", opts.province);
      if (opts.ownerId) p.set("owner_id", opts.ownerId);
      if (opts.sort) p.set("sort", opts.sort);
      return call(API + "?" + p.toString());
    },

    async getAnimal(id) {
      if (!id) return null;
      const b = await call(API + "?action=animal&id=" + encodeURIComponent(id));
      return b.animal || null;
    },

    async saveAnimal(animal) {
      const b = await call(API + "?action=animal_save", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ animal }),
      });
      return b.id;
    },

    async deleteAnimal(id) {
      return call(API + "?action=animal_delete", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ id }),
      });
    },

    async offspring(id) {
      const b = await call(API + "?action=offspring&id=" + encodeURIComponent(id));
      return b.rows || [];
    },

    async stats() {
      return call(API + "?action=stats");
    },

    /* Server-computed herd-genetics metrics (avg F, generation interval, Ne). */
    async herdStats() {
      return call(API + "?action=herd_stats");
    },

    /* Atomically reserve the next tag serial for a region+breed key. */
    async nextTag(key, start) {
      const b = await call(
        API + "?action=next_tag&key=" + encodeURIComponent(key) + "&start=" + (start || 1)
      );
      return b.n;
    },

    /* Phase 3 — whole-herd analytics (server-side subgraphs & reports). */

    /* Ancestor subgraph of one animal (up to depth gens) — for Deep Pedigree
       + its inbreeding/diversity panels. Returns mapped animal rows. */
    async pedigree(id, depth) {
      const b = await call(API + "?action=pedigree&id=" + encodeURIComponent(id) + "&depth=" + (depth || 11));
      return b.rows || [];
    },

    /* Merged ancestor subgraphs for several animals — for the Kinship matrix. */
    async ancestorsBatch(ids, depth) {
      const b = await call(API + "?action=ancestors_batch&ids=" + encodeURIComponent((ids || []).join(",")) + "&depth=" + (depth || 6));
      return b.rows || [];
    },

    async founders(page, perPage) {
      const b = await call(API + "?action=founders&page=" + (page || 1) + "&per_page=" + (perPage || 50));
      return b;
    },

    async topAncestors(limit) {
      const b = await call(API + "?action=top_ancestors&limit=" + (limit || 15));
      return b.rows || [];
    },

    async herdReport(page, perPage) {
      const b = await call(API + "?action=herd_report&page=" + (page || 1) + "&per_page=" + (perPage || 50));
      return b;
    },

    /* Save a browser-computed inbreeding F so the herd report can sort at scale. */
    async setF(id, f, avk) {
      return call(API + "?action=set_f", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ id, f, avk }),
      });
    },

    async setting(k) {
      const b = await call(API + "?action=setting&k=" + encodeURIComponent(k));
      return b.data;
    },
    async settingSave(k, data) {
      return call(API + "?action=setting_save&k=" + encodeURIComponent(k), {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ data }),
      });
    },
  };

  window.LpDB = LpDB;
})();
