// supabase-client.jsx — singleton Supabase client for the diaval site.
// Loaded after the supabase-js UMD CDN script (which exposes window.supabase),
// this assigns window.diavalSupabase for all page scripts to share.
//
// Note on the embedded key: the publishable key is *designed* to be public.
// Security comes from Row Level Security policies on the database, not from
// hiding this string. See the diaval_* RLS policies in the migration.

const SUPABASE_URL = "https://ewehdfzcfjbzrlhgedxv.supabase.co";
// Using the legacy anon JWT key (not the newer sb_publishable_ key). Both are
// public-by-design with the same security model (RLS enforces access), but
// Supabase Functions with verify_jwt=true require a JWT-format key — the
// publishable key isn't a JWT, so it gets 401'd at the gateway.
const SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImV3ZWhkZnpjZmpienJsaGdlZHh2Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzE5ODc5MzcsImV4cCI6MjA4NzU2MzkzN30.AAR6FXb1Abr1r2nMWzlk7d1rsTDSQNqUH97yZLrPngA";

// In-memory cache for read-mostly data. Keyed by string. Persists across
// tab switches because it lives on `window`, not in any component's state.
// Any page that fetches "rarely changing" data (myths, transmissions, about
// config, etc.) should pipe its fetcher through diavalCachedFetch so the
// second navigation back to that page doesn't trigger another round-trip.
//
//   const data = await window.diavalCachedFetch("myths-public-list", () =>
//     sb.from("diaval_myths_public").select("...").then(r => r.data || []));
//
// Pair with `window.diavalCacheGet(key)` for synchronous initial-state reads
// so a component renders with data on the first paint instead of flashing
// through a loading state on every revisit.
window._diavalCache = window._diavalCache || new Map();

window.diavalCacheGet = function (key) {
  const e = window._diavalCache.get(key);
  if (!e) return null;
  // 5-minute TTL by default — fresh enough that admin saves appear quickly,
  // stable enough that hopping between tabs doesn't refetch.
  if (Date.now() - e.t > 5 * 60 * 1000) { window._diavalCache.delete(key); return null; }
  return e.v;
};

window.diavalCachedFetch = async function (key, fetcher, ttlMs = 5 * 60 * 1000) {
  const e = window._diavalCache.get(key);
  if (e && Date.now() - e.t < ttlMs) return e.v;
  const v = await fetcher();
  window._diavalCache.set(key, { v, t: Date.now() });
  return v;
};

window.diavalCacheBust = function (prefix) {
  if (!prefix) { window._diavalCache.clear(); return; }
  for (const k of Array.from(window._diavalCache.keys())) {
    if (k.startsWith(prefix)) window._diavalCache.delete(k);
  }
};

window.diavalSupabase = window.supabase.createClient(
  SUPABASE_URL,
  SUPABASE_ANON_KEY
);
// Exposed for raw fetch from helpers (e.g. window.diavalEngage) that don't go through supabase-js.
window.diavalSupabaseUrl = SUPABASE_URL;
window.diavalSupabaseAnonKey = SUPABASE_ANON_KEY;

// Shared helper for invoking edge functions. Uses supabase-js's `functions.invoke`
// which handles the Authorization header (publishable key) automatically — manual
// header construction was returning 401 because `sb.supabaseKey` isn't a public
// property of the v2 client.
window.diavalCallFunction = async function(name, body) {
  const sb = window.diavalSupabase;
  const { data, error } = await sb.functions.invoke(name, { body });
  if (error) {
    let serverMsg = null;
    let status = error.context?.status ?? error.status;
    // error.context is the raw Response — read as text first (works regardless of
    // content-type), then try to parse JSON for a structured error message.
    if (error.context && typeof error.context.text === "function") {
      try {
        const txt = await error.context.text();
        if (txt) {
          try {
            const parsed = JSON.parse(txt);
            serverMsg = parsed?.error || parsed?.message || txt;
          } catch (_) {
            serverMsg = txt.slice(0, 500);
          }
        }
      } catch (_) {}
    }
    const prefix = status ? `[${status}] ` : "";
    throw new Error(prefix + (serverMsg || error.message || "Request failed"));
  }
  return data;
};

// Upload an image to the diaval Storage bucket with EXIF stripped client-side first.
// Calls window.stripImageMetadata (canvas re-encode) then POSTs to admin-upload edge fn.
// adminKey is required and gates the writer; the bucket is otherwise public for reads.
window.diavalUploadImage = async function (file, { bucket = "diaval", folder = "general", filename, adminKey } = {}) {
  if (!adminKey) throw new Error("adminKey is required");
  if (!window.stripImageMetadata) throw new Error("stripImageMetadata not loaded");

  const stripped = await window.stripImageMetadata(file);

  const baseName = filename
    ? window.slugifyFilename(filename)
    : window.slugifyFilename(file.name || "image");
  const path = `${folder.replace(/\/+$/, "")}/${baseName}.${stripped.extension}`;

  const form = new FormData();
  form.append("admin_key", adminKey);
  form.append("bucket", bucket);
  form.append("path", path);
  form.append("file", stripped.blob, `${baseName}.${stripped.extension}`);

  // Use raw fetch — supabase-js functions.invoke serializes JSON; we need multipart.
  const res = await fetch(`${SUPABASE_URL}/functions/v1/admin-upload`, {
    method: "POST",
    headers: {
      // anon JWT required by verify_jwt=true; admin_key in the body is the real auth
      Authorization: `Bearer ${SUPABASE_ANON_KEY}`,
      apikey: SUPABASE_ANON_KEY,
    },
    body: form,
  });
  let payload;
  try { payload = await res.json(); } catch { payload = null; }
  if (!res.ok) {
    throw new Error(`[${res.status}] ${(payload && payload.error) || "Upload failed"}`);
  }
  return {
    public_url: payload.public_url,
    path: payload.path,
    bucket: payload.bucket,
    size: payload.size,
    original_size: stripped.originalSize,
    content_type: payload.content_type,
    width: stripped.width,
    height: stripped.height,
    detected_format: stripped.detectedFormat,
    animated_source_warning: stripped.animatedSourceWarning,
  };
};
