/* Supabase browser client for auth and checkout. Public config lives in store-config.js. */

const STORE_CONFIG = window.GFV_CONFIG || {};
let storeClient = null;
const GOOGLE_AUTH_PENDING_KEY = "gfv_google_auth_pending";

function hasStoreConfig() {
  return Boolean(STORE_CONFIG.supabaseUrl && STORE_CONFIG.supabasePublishableKey);
}

function getStoreClient() {
  if (!hasStoreConfig()) {
    throw new Error("Add the Supabase URL and publishable key in src/store-config.js.");
  }
  if (!window.supabase?.createClient) {
    throw new Error("Supabase client library did not load.");
  }
  if (!storeClient) {
    storeClient = window.supabase.createClient(
      STORE_CONFIG.supabaseUrl,
      STORE_CONFIG.supabasePublishableKey
    );
  }
  return storeClient;
}

function toStoreUser(user) {
  if (!user) return null;
  return {
    id: user.id,
    email: user.email || "",
    name: user.user_metadata?.full_name || user.user_metadata?.name || user.email || "Google user",
  };
}

async function watchStoreUser(onChange) {
  if (!hasStoreConfig()) return () => {};

  const client = getStoreClient();
  const { data } = await client.auth.getSession();
  onChange(toStoreUser(data.session?.user));

  const authListener = client.auth.onAuthStateChange((_event, session) => {
    onChange(toStoreUser(session?.user));
  });

  return () => authListener.data.subscription.unsubscribe();
}

function getStoreAuthCallbackError() {
  const query = new URLSearchParams(window.location.search);
  const hash = new URLSearchParams(window.location.hash.replace(/^#/, ""));
  const authError = hash.get("error_description") || query.get("error_description");
  return authError ? decodeURIComponent(authError.replace(/\+/g, " ")) : "";
}

function getStoreAuthRedirectUrl() {
  if (STORE_CONFIG.authRedirectUrl) return STORE_CONFIG.authRedirectUrl;
  if (!/^https?:$/.test(window.location.protocol)) {
    throw new Error("Google login needs an http(s) URL. Open this page from localhost or the deployed site.");
  }
  return `${window.location.origin}${window.location.pathname}`;
}

async function signInWithGoogle() {
  const client = getStoreClient();
  sessionStorage.setItem(GOOGLE_AUTH_PENDING_KEY, "dashboard");
  const { error } = await client.auth.signInWithOAuth({
    provider: "google",
    options: {
      redirectTo: getStoreAuthRedirectUrl(),
    },
  });
  if (error) {
    sessionStorage.removeItem(GOOGLE_AUTH_PENDING_KEY);
    throw error;
  }
}

function consumeGoogleAuthReturnPath() {
  const returnPath = sessionStorage.getItem(GOOGLE_AUTH_PENDING_KEY);
  sessionStorage.removeItem(GOOGLE_AUTH_PENDING_KEY);
  return returnPath;
}

async function signOutStoreUser() {
  if (!hasStoreConfig()) return;
  const { error } = await getStoreClient().auth.signOut();
  if (error) throw error;
}

function isAdminEmail(email) {
  const admins = STORE_CONFIG.adminEmails || [];
  return admins.includes((email || "").toLowerCase());
}

async function adminGetFonts() {
  const { data, error } = await getStoreClient().from("fonts").select("*").order("created_at", { ascending: false });
  if (error) throw error;
  return data || [];
}

async function adminUpsertFont(font) {
  const { data, error } = await getStoreClient().from("fonts").upsert(font, { onConflict: "id" }).select().single();
  if (error) throw error;
  return data;
}

async function adminDeleteFont(id) {
  const { error } = await getStoreClient().from("fonts").delete().eq("id", id);
  if (error) throw error;
}

async function adminGetOrders() {
  const { data, error } = await getStoreClient().from("orders").select("*").order("created_at", { ascending: false });
  if (error) throw error;
  return data || [];
}

async function uploadFontAsset(file, folder) {
  const ext = file.name.split(".").pop();
  const path = `${folder}/${Date.now()}-${Math.random().toString(36).slice(2)}.${ext}`;
  const { error } = await getStoreClient().storage.from("font-assets").upload(path, file);
  if (error) throw error;
  const { data } = getStoreClient().storage.from("font-assets").getPublicUrl(path);
  return data.publicUrl;
}

function normalizeFont(f) {
  const langs = Array.isArray(f.languages) ? f.languages : [];
  return {
    ...f,
    image: f.image_url || null,
    collection: f.category || "all",
    tags: Array.isArray(f.tags) ? f.tags : [],
    weights: Array.isArray(f.weights) ? f.weights.map(Number) : [400],
    languages: langs.map(l => l === "latin" ? "english" : l),
    color: f.color || "butter",
    sample_size: Number(f.sample_size) || 64,
    featured: Boolean(f.featured),
    new: Boolean(f.new),
    hot: Boolean(f.hot),
    special_files: (typeof f.special_files === "object" && f.special_files !== null) ? f.special_files : {},
  };
}

async function loadPublicFonts() {
  if (!hasStoreConfig()) return [];
  const { data, error } = await getStoreClient().from("fonts").select("*").order("created_at", { ascending: false });
  if (error) { console.warn("Failed to load fonts:", error); return []; }
  return (data || []).map(normalizeFont);
}

function injectFontFaces(fonts) {
  const old = document.getElementById("gfv-font-faces");
  if (old) old.remove();
  const rules = [];
  for (const font of fonts) {
    const m = (font.family || "").match(/['"]?([^,'"]+)['"]?/);
    if (!m) continue;
    const name = m[1].trim();
    if (!name) continue;
    const files = font.font_files || {};
    let injected = false;
    for (const [w, url] of Object.entries(files)) {
      if (url) {
        rules.push(`@font-face{font-family:"${name}";src:url("${url}");font-weight:${w};font-display:swap;}`);
        injected = true;
      }
    }
    if (!injected && font.font_url) {
      rules.push(`@font-face{font-family:"${name}";src:url("${font.font_url}");font-display:swap;}`);
    }
    for (const [variantName, url] of Object.entries(font.special_files || {})) {
      if (url) rules.push(`@font-face{font-family:"${name} ${variantName}";src:url("${url}");font-display:swap;}`);
    }
  }
  if (rules.length) {
    const style = document.createElement("style");
    style.id = "gfv-font-faces";
    style.textContent = rules.join("\n");
    document.head.appendChild(style);
  }
}

async function createPendingOrder({ email, items, total }) {
  const normalizedItems = items.map(i => ({
    fontId: i.id, name: i.name, licenseTier: i.licenseTier, price: i.price,
  }));
  const { data, error } = await getStoreClient().from("orders").insert({
    user_email: email.toLowerCase(),
    items: normalizedItems,
    total,
    status: "pending",
  }).select().single();
  if (error) throw error;
  return data;
}

async function submitSlip(slipFile, orderId, expectedTotal) {
  const ext = slipFile.name.split(".").pop();
  const path = `slips/${orderId}.${ext}`;
  const { error: upErr } = await getStoreClient().storage.from("slips").upload(path, slipFile, { upsert: true });
  if (upErr) throw upErr;
  const { data: urlData } = getStoreClient().storage.from("slips").getPublicUrl(path);
  const slipUrl = urlData.publicUrl;

  const { error: updateErr } = await getStoreClient().from("orders").update({ slip_url: slipUrl, status: "slip_submitted" }).eq("id", orderId);
  if (updateErr) console.warn("Frontend order update failed (edge fn will handle):", updateErr);

  if (STORE_CONFIG.easyslipEnabled) {
    const { data, error } = await getStoreClient().functions.invoke("verify-slip", {
      body: { orderId, slipUrl, expectedTotal },
    });
    if (error) throw new Error(error.message);
    return data;
  }
  return { verified: false, manual: true };
}

async function adminApproveOrder(orderId) {
  const { error } = await getStoreClient().from("orders").update({ status: "paid" }).eq("id", orderId);
  if (error) throw error;
}

async function adminRejectOrder(orderId) {
  const { error } = await getStoreClient().from("orders").update({ status: "rejected" }).eq("id", orderId);
  if (error) throw error;
}

function createOmiseCardToken(cardData) {
  return new Promise((resolve, reject) => {
    const key = STORE_CONFIG.omisePublicKey;
    if (!key) { reject(new Error("เพิ่ม omisePublicKey ใน store-config.js")); return; }
    if (!window.Omise) { reject(new Error("Omise.js ยังไม่โหลด")); return; }
    window.Omise.setPublicKey(key);
    window.Omise.createToken("card", cardData, (code, resp) => {
      if (code !== 200 || resp.object === "error") reject(new Error(resp.message || "ข้อมูลบัตรไม่ถูกต้อง"));
      else resolve(resp.id);
    });
  });
}

async function chargeOmise({ token, email, items, total, promptpay = false }) {
  const { data, error } = await getStoreClient().functions.invoke("omise-payment", {
    body: { action: "charge", token, email, items, total, promptpay },
  });
  if (error) throw new Error(error.message || "ชำระเงินไม่สำเร็จ");
  if (data?.error) throw new Error(data.error);
  return data;
}

async function checkOmiseCharge(chargeId) {
  const { data, error } = await getStoreClient().functions.invoke("omise-payment", {
    body: { action: "check", chargeId },
  });
  if (error) return false;
  return data?.paid === true;
}

async function getUserOrders(email) {
  if (!email || !hasStoreConfig()) return [];
  const { data, error } = await getStoreClient()
    .from("orders")
    .select("*")
    .eq("user_email", email.toLowerCase())
    .order("created_at", { ascending: false });
  if (error) { console.warn("Orders load failed:", error); return []; }
  return data || [];
}

async function createFontCheckout({ email, items }) {
  const normalizedItems = items.map(item => ({
    fontId: item.id,
    licenseTier: item.licenseTier || "personal",
  }));
  const { data, error } = await getStoreClient().functions.invoke("create-checkout", {
    body: {
      email,
      items: normalizedItems,
      origin: window.location.origin,
    },
  });

  if (error) throw error;
  if (!data?.url) throw new Error("Checkout session did not return a redirect URL.");
  return data.url;
}

Object.assign(window, {
  hasStoreConfig,
  getStoreClient,
  getStoreAuthCallbackError,
  watchStoreUser,
  signInWithGoogle,
  consumeGoogleAuthReturnPath,
  signOutStoreUser,
  createPendingOrder,
  submitSlip,
  adminApproveOrder,
  adminRejectOrder,
  createOmiseCardToken,
  chargeOmise,
  checkOmiseCharge,
  getUserOrders,
  isAdminEmail,
  adminGetFonts,
  adminUpsertFont,
  adminDeleteFont,
  adminGetOrders,
  uploadFontAsset,
  loadPublicFonts,
  injectFontFaces,
});
