const BASE = process.env.NEXT_PUBLIC_API_URL || "http://localhost:4000/api";

const AFFILIATE_KEY = "pn_affiliate";

/**
 * Attach the right bearer token so the backend knows who's calling:
 *  - Merchant admin (embedded in Shopify): an App Bridge session token.
 *  - Affiliate portal: the signed token issued at login (stored locally).
 * The two contexts never overlap (different pages), so we pick whichever exists.
 */
/**
 * Public read-only demo. Once /admin?demo=1 is opened, the flag sticks in the
 * session so the whole preview (and its client-side navigation) keeps sending
 * the demo header instead of a session token.
 */
export function isDemo(): boolean {
  if (typeof window === "undefined") return false;
  try {
    const p = new URLSearchParams(window.location.search);
    if (p.get("demo") === "1") {
      sessionStorage.setItem("tk_demo", "1");
      return true;
    }
    return sessionStorage.getItem("tk_demo") === "1";
  } catch {
    return false;
  }
}

/**
 * Which store's affiliate program are we on? The merchant shares a signup/login
 * link with `?shop=<store>.myshopify.com` baked in (see the admin's Important
 * links). We remember it so the public signup/login/portal pages all talk to the
 * SAME merchant the affiliate is joining — never the shared default store. The
 * embedded admin (/admin) is skipped: it authenticates with a session token and
 * its URL's ?shop must not leak into the affiliate context.
 */
const SHOP_KEY = "pn_shop";
export function currentShopParam(): string | null {
  if (typeof window === "undefined") return null;
  try {
    if (window.location.pathname.startsWith("/admin")) return null;
    const s = new URLSearchParams(window.location.search).get("shop");
    if (s && /^[a-z0-9][a-z0-9-]*\.myshopify\.com$/i.test(s)) {
      localStorage.setItem(SHOP_KEY, s);
      return s;
    }
    return localStorage.getItem(SHOP_KEY);
  } catch {
    return null;
  }
}

async function authHeaders(): Promise<Record<string, string>> {
  if (typeof window === "undefined") return {};

  // Public demo — no token, just the demo marker (server serves demo data, GET-only).
  if (isDemo()) return { "x-demo": "1" };

  // Embedded admin — App Bridge session token (present only when initialized).
  try {
    const { appSessionToken } = await import("./app-bridge");
    const t = await appSessionToken();
    if (t) return { Authorization: `Bearer ${t}` };
  } catch {
    /* not embedded / App Bridge not ready — fall through */
  }

  // Affiliate portal / public signup pages. Send the stored login token (if any)
  // AND the shop the page is scoped to, so token-less calls (signup-config,
  // signup, login) still resolve the correct merchant.
  const headers: Record<string, string> = {};
  try {
    const raw = localStorage.getItem(AFFILIATE_KEY);
    const token = raw ? (JSON.parse(raw) as { token?: string }).token : null;
    if (token) headers.Authorization = `Bearer ${token}`;
  } catch {
    /* ignore */
  }
  const shop = currentShopParam();
  if (shop) headers["x-shop-domain"] = shop;
  return headers;
}

async function req(path: string, opts?: RequestInit) {
  const auth = await authHeaders();
  const res = await fetch(BASE + path, {
    ...opts,
    headers: { "content-type": "application/json", ...auth, ...(opts?.headers || {}) },
  });
  const body = await res.json().catch(() => null);
  if (!res.ok) throw new Error(body?.message || `Request failed (${res.status})`);
  return body;
}

export const api = {
  base: BASE,
  get: (p: string) => req(p),
  post: (p: string, body?: unknown) =>
    req(p, { method: "POST", body: JSON.stringify(body ?? {}) }),
  put: (p: string, body?: unknown) =>
    req(p, { method: "PUT", body: JSON.stringify(body ?? {}) }),
  del: (p: string) => req(p, { method: "DELETE" }),
};

// Client-side auth for the affiliate portal. `token` is the signed session
// token from login — sent as a Bearer token on every request; the backend
// derives the affiliate id from it (the URL id is no longer trusted).
export const auth = {
  save: (id: string, name: string, token?: string) => {
    const prev = auth.get();
    localStorage.setItem(
      AFFILIATE_KEY,
      JSON.stringify({ id, name, token: token ?? prev?.token ?? null }),
    );
  },
  get: (): { id: string; name: string; token?: string | null } | null => {
    try {
      return JSON.parse(localStorage.getItem(AFFILIATE_KEY) || "null");
    } catch {
      return null;
    }
  },
  clear: () => localStorage.removeItem(AFFILIATE_KEY),
};
