import { useCallback, useEffect, useRef, useState } from "react";
import { createClient } from "@metagptx/web-sdk";

const client = createClient();

/**
 * Site settings are stored as key-value rows in the `site_settings` entity.
 * Each row: { id, key, value_json: "<stringified JSON>" }.
 *
 * This hook loads the row for the given key, exposes a typed value, and
 * saves back to the backend (upsert semantics).
 */
export function useSiteSettings<T>(key: string, defaults: T) {
  const [value, setValue] = useState<T>(defaults);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [rowId, setRowId] = useState<number | null>(null);
  const mountedRef = useRef(true);

  useEffect(() => {
    mountedRef.current = true;
    return () => {
      mountedRef.current = false;
    };
  }, []);

  const load = useCallback(async () => {
    setLoading(true);
    try {
      // Public data -> queryAll so all users (incl. anonymous) can read.
      const resp: any = await (client.entities as any).site_settings.queryAll({
        query: { key },
        limit: 1,
      });
      const items = resp?.data?.items ?? [];
      if (items.length > 0) {
        const row = items[0];
        try {
          const parsed = JSON.parse(row.value_json ?? "{}");
          if (mountedRef.current) {
            setValue({ ...defaults, ...parsed });
            setRowId(row.id);
          }
        } catch {
          if (mountedRef.current) setValue(defaults);
        }
      } else {
        if (mountedRef.current) setValue(defaults);
      }
    } catch (e) {
      // Fall back to localStorage mirror so admins can still edit when offline
      try {
        const raw = localStorage.getItem(`site_settings:${key}`);
        if (raw && mountedRef.current) {
          setValue({ ...defaults, ...JSON.parse(raw) });
        }
      } catch {
        /* ignore */
      }
    } finally {
      if (mountedRef.current) setLoading(false);
    }
  }, [key]);

  useEffect(() => {
    load();
  }, [load]);

  const save = useCallback(
    async (next?: T) => {
      const payload = next ?? value;
      setSaving(true);
      const serialized = JSON.stringify(payload);
      try {
        if (rowId != null) {
          await (client.entities as any).site_settings.update({
            id: rowId,
            data: { key, value_json: serialized },
          });
        } else {
          // Check once more in case another tab created it
          const existing: any = await (client.entities as any).site_settings.queryAll({
            query: { key },
            limit: 1,
          });
          const items = existing?.data?.items ?? [];
          if (items.length > 0) {
            await (client.entities as any).site_settings.update({
              id: items[0].id,
              data: { key, value_json: serialized },
            });
            setRowId(items[0].id);
          } else {
            const created: any = await (client.entities as any).site_settings.create({
              data: { key, value_json: serialized },
            });
            if (created?.data?.id) setRowId(created.data.id);
          }
        }
        localStorage.setItem(`site_settings:${key}`, serialized);
        // Let other tabs / providers know
        window.dispatchEvent(new CustomEvent("site_settings:updated", { detail: { key } }));
        return { ok: true };
      } catch (e: any) {
        // Persist locally so the admin's work isn't lost if the backend is down
        localStorage.setItem(`site_settings:${key}`, serialized);
        return { ok: false, error: e?.message ?? "Save failed" };
      } finally {
        if (mountedRef.current) setSaving(false);
      }
    },
    [rowId, key, value],
  );

  return { value, setValue, save, load, loading, saving };
}

/**
 * Lightweight read-only loader for public pages (e.g. Login / Pricing / Header).
 * Reads from localStorage first for instant paint, then refreshes from backend.
 */
export function useSiteSettingsRead<T>(key: string, defaults: T) {
  const [value, setValue] = useState<T>(() => {
    try {
      const raw = localStorage.getItem(`site_settings:${key}`);
      if (raw) return { ...defaults, ...JSON.parse(raw) };
    } catch {
      /* ignore */
    }
    return defaults;
  });

  useEffect(() => {
    let alive = true;
    const fetchIt = async () => {
      try {
        const resp: any = await (client.entities as any).site_settings.queryAll({
          query: { key },
          limit: 1,
        });
        const items = resp?.data?.items ?? [];
        if (items.length > 0 && alive) {
          try {
            const parsed = JSON.parse(items[0].value_json ?? "{}");
            setValue({ ...defaults, ...parsed });
            localStorage.setItem(`site_settings:${key}`, JSON.stringify(parsed));
          } catch {
            /* ignore */
          }
        }
      } catch {
        /* ignore - we already have defaults/cache */
      }
    };
    fetchIt();
    const onUpdate = (ev: Event) => {
      const ce = ev as CustomEvent;
      if (ce?.detail?.key === key) fetchIt();
    };
    window.addEventListener("site_settings:updated", onUpdate);
    return () => {
      alive = false;
      window.removeEventListener("site_settings:updated", onUpdate);
    };
  }, [key]);

  return value;
}