/* remote-store.jsx — bản useStore / useAuth chạy thật trên Supabase.
 *
 * Giữ NGUYÊN hợp đồng mà UI đang dùng (project/photo shape + tên method) để
 * không phải sửa các view. Chỉ kích hoạt khi config.js đã điền anon key;
 * nếu chưa, store.jsx/auth.jsx tự dùng bản localStorage cũ.
 */

/* Có cấu hình Supabase hay chưa — đọc đồng bộ từ config.js (chạy trước cloud.js). */
function cpConfigured() {
  const c = window.__CP_CONFIG__ || {};
  return !!(c.SUPABASE_URL && c.SUPABASE_ANON_KEY) && !/[<>]/.test(c.SUPABASE_ANON_KEY);
}
window.cpConfigured = cpConfigured;

/* Chờ cloud.js (module, nạp bất đồng bộ) sẵn sàng. */
function useCloudReady() {
  const [ready, setReady] = React.useState(!!window.CP_CLOUD);
  React.useEffect(() => {
    if (window.CP_CLOUD) { setReady(true); return; }
    const on = () => setReady(true);
    window.addEventListener("cp-cloud-ready", on);
    return () => window.removeEventListener("cp-cloud-ready", on);
  }, []);
  return ready;
}

/* =========================================================================
 * AUTH (Supabase)
 * ===================================================================== */
function useRemoteAuth() {
  const ready = useCloudReady();
  const [user, setUser] = React.useState(null);
  const [booted, setBooted] = React.useState(false);

  React.useEffect(() => {
    if (!ready) return;
    const cloud = window.CP_CLOUD;
    let unsub = () => {};
    cloud.auth.currentUser().then((u) => { setUser(u); setBooted(true); }).catch(() => setBooted(true));
    const sub = cloud.auth.onChange(async () => {
      try { setUser(await cloud.auth.currentUser()); } catch (e) { setUser(null); }
    });
    unsub = sub && sub.data && sub.data.subscription ? () => sub.data.subscription.unsubscribe() : () => {};
    return unsub;
  }, [ready]);

  return {
    configured: true,
    user,
    booted,
    auth: window.CP_CLOUD ? window.CP_CLOUD.auth : null,
    async logout() {
      setUser(null);                       // về màn đăng nhập ngay, không chờ mạng
      try { if (window.CP_CLOUD) await window.CP_CLOUD.auth.signOut(); } catch (e) {}
    },
    // giữ chữ ký cũ cho an toàn (không dùng trong chế độ cấu hình)
    grantProject() {},
  };
}
window.useRemoteAuth = useRemoteAuth;

/* =========================================================================
 * STORE (Supabase + R2)
 * ===================================================================== */
function useRemoteStore() {
  const ready = useCloudReady();
  const [data, setData] = React.useState({ projects: [], photos: [] });
  const meRef = React.useRef(null);
  const loadedRef = React.useRef(new Set());   // project ids đã nạp ảnh
  const subsRef = React.useRef({});            // project id → unsub realtime

  const db = () => window.CP_CLOUD.db;

  const reloadProjects = React.useCallback(async () => {
    try {
      const projects = await db().listProjects();
      setData((d) => ({ ...d, projects }));
    } catch (e) { console.error("listProjects", e); }
  }, []);

  const loadPhotos = React.useCallback(async (projectId) => {
    try {
      const photos = await db().listPhotos(projectId, meRef.current);
      setData((d) => ({ ...d, photos: [...d.photos.filter((p) => p.projectId !== projectId), ...photos] }));
    } catch (e) { console.error("listPhotos", e); }
  }, []);

  // boot: lấy user hiện tại + nạp danh sách project
  React.useEffect(() => {
    if (!ready) return;
    let alive = true;
    (async () => {
      try { const u = await window.CP_CLOUD.auth.currentUser(); meRef.current = u ? u.id : null; } catch (e) {}
      if (alive) await reloadProjects();
    })();
    const offAuth = window.CP_CLOUD.auth.onChange(async () => {
      try { const u = await window.CP_CLOUD.auth.currentUser(); meRef.current = u ? u.id : null; } catch (e) { meRef.current = null; }
      loadedRef.current = new Set();
      setData({ projects: [], photos: [] });
      await reloadProjects();
    });
    return () => {
      alive = false;
      if (offAuth && offAuth.data && offAuth.data.subscription) offAuth.data.subscription.unsubscribe();
      Object.values(subsRef.current).forEach((fn) => { try { fn(); } catch (e) {} });
      subsRef.current = {};
    };
  }, [ready, reloadProjects]);

  const ensurePhotos = React.useCallback((projectId) => {
    if (loadedRef.current.has(projectId)) return;
    loadedRef.current.add(projectId);
    setTimeout(() => loadPhotos(projectId), 0);
    // realtime: nghe thay đổi để studio thấy khách chọn ngay
    let timer = null;
    subsRef.current[projectId] = window.CP_CLOUD.db.subscribeProject(projectId, () => {
      clearTimeout(timer); timer = setTimeout(() => loadPhotos(projectId), 250);
    });
  }, [loadPhotos]);

  const patchPhoto = React.useCallback((id, patch) => {
    setData((d) => ({ ...d, photos: d.photos.map((p) => p.id === id ? { ...p, ...(typeof patch === "function" ? patch(p) : patch) } : p) }));
  }, []);

  const api = React.useMemo(() => ({
    _data: data,
    _remote: true,

    src(photo) {
      if (!photo) return "";
      if (photo.url) return photo.url;
      if (photo.seed != null && window.makePhoto) return window.makePhoto(photo.seed, photo.w, photo.h);
      return "";
    },
    // bản nhỏ cho lưới/thumbnail
    thumb(photo, w) {
      if (!photo) return "";
      if (photo.url && window.cpResizeUrl) return window.cpResizeUrl(photo.url, w || 480);
      return this.src(photo);
    },
    project(id) { return data.projects.find((p) => p.id === id); },
    projectPhotos(id) { ensurePhotos(id); return data.photos.filter((p) => p.projectId === id); },

    async reload() { await reloadProjects(); },

    async addProject(input) {
      const id = await db().addProject(input);
      await reloadProjects();
      return id;
    },
    async addAlbum(projectId, name) {
      const id = await db().addAlbum(projectId, name);
      await reloadProjects();
      return id;
    },
    projectByCode() { return null; }, // chế độ thật: dùng redeemCode (xem AddCodeModal)

    // mời khách thủ công không lưu được (schema yêu cầu khách tự đăng nhập + nhập mã).
    addGuest() {},
    async removeGuest(projectId, emailOrProfileId) {
      const proj = data.projects.find((p) => p.id === projectId);
      const g = proj && (proj.guests || []).find((x) => x.email === emailOrProfileId || x.profileId === emailOrProfileId);
      const pid = g ? g.profileId : emailOrProfileId;
      if (!pid) return;
      await db().removeGuest(projectId, pid);
      await reloadProjects();
    },

    async addUploads(projectId, albumId, files, onProgress) {
      // chống trùng tên hiển thị trong cùng project (object trên R2 đã unique nhờ UUID)
      const taken = new Set(data.photos.filter((p) => p.projectId === projectId).map((p) => p.filename));
      let done = 0;
      for (const file of files) {
        const filename = uniqueName(file.name, taken);
        const dims = await fileImgDims(file);
        const { key, bucket, url } = await window.CP_CLOUD.uploadToR2(projectId, file);
        const row = await db().insertPhoto({ projectId, albumId, file, filename, key, bucket, url, w: dims.w, h: dims.h });
        const mapped = window.CP_CLOUD.db.mapPhoto(row, meRef.current);
        setData((d) => ({ ...d, photos: [mapped, ...d.photos] }));
        done++; onProgress && onProgress(done, files.length, file.name);
      }
      return files.length;
    },

    setStars(id, n) {
      patchPhoto(id, (p) => ({ stars: p.stars === n ? 0 : n }));
      const next = (data.photos.find((p) => p.id === id) || {}).stars === n ? 0 : n;
      db().setStars(id, next).catch((e) => console.error(e));
    },
    toggleLike(id) {
      let nv = false;
      patchPhoto(id, (p) => { nv = !p.liked; return { liked: nv }; });
      db().toggleLike(id, nv).catch((e) => console.error(e));
    },
    setStatus(id, s) {
      let nv = "none";
      patchPhoto(id, (p) => { nv = p.status === s ? "none" : s; return { status: nv }; });
      db().setStatus(id, nv).catch((e) => console.error(e));
    },
    setNote(id, note) {
      patchPhoto(id, { note });
      db().setNote(id, note).catch((e) => console.error(e));
    },
    addComment(id, comment) {
      patchPhoto(id, (p) => ({ comments: [...(p.comments || []), comment] }));
      db().addComment(id, comment.text).catch((e) => console.error(e));
    },
    moveToAlbum(id, albumId) {
      patchPhoto(id, { albumId });
      db().moveToAlbum(id, albumId).catch((e) => console.error(e));
    },
    deletePhoto(id) {
      patchPhoto(id, null); // optimistic remove below
      setData((d) => ({ ...d, photos: d.photos.filter((p) => p.id !== id) }));
      db().deletePhoto(id).catch((e) => console.error(e));
    },
    resetAll() { reloadProjects(); },
  }), [data, ensurePhotos, patchPhoto, reloadProjects]);

  return api;
}
window.useRemoteStore = useRemoteStore;

function fileImgDims(file) {
  return new Promise((res) => {
    const url = URL.createObjectURL(file);
    const im = new Image();
    im.onload = () => { res({ w: im.naturalWidth, h: im.naturalHeight }); URL.revokeObjectURL(url); };
    im.onerror = () => { res({ w: 600, h: 600 }); URL.revokeObjectURL(url); };
    im.src = url;
  });
}

function uniqueName(name, taken) {
  let cand = name;
  if (taken.has(cand)) {
    const dot = name.lastIndexOf(".");
    const base = dot > 0 ? name.slice(0, dot) : name;
    const ext = dot > 0 ? name.slice(dot) : "";
    let i = 2;
    do { cand = base + " (" + i + ")" + ext; i++; } while (taken.has(cand));
  }
  taken.add(cand);
  return cand;
}
