/**
 * push.ts — Pushe (Iran-safe) push notification glue for the Capacitor shell.
 *
 * On the web (browser) these calls are inert no-ops; they only do real work
 * inside the native Android shell where `cordova-plugin-pushe` injects the
 * global `window.Pushe` object.
 *
 * Topics
 *   city-{slug}   → marketing / new-café pushes for a city
 *   cafe-{slug}   → saved-café alerts (new menu, events, status)
 * Per-device token → targeted order / reservation updates (registered to backend)
 *
 * Backend contract (to implement):
 *   POST /api/public/push/register   { token, platform: "android", city?, savedCafes?: string[] }
 *   POST /api/public/push/unregister { token }
 */

const API_URL = process.env.NEXT_PUBLIC_API_URL ?? "https://api.meezi.ir";

interface PusheBridge {
  initialize?: (success?: () => void, error?: (e: unknown) => void) => void;
  getDeviceId?: (cb: (id: string) => void) => void;
  subscribe: (topic: string) => void;
  unsubscribe: (topic: string) => void;
  setUserConsent?: (granted: boolean) => void;
}

function bridge(): PusheBridge | null {
  if (typeof window === "undefined") return null;
  return (window as unknown as { Pushe?: PusheBridge }).Pushe ?? null;
}

/** True only inside the native Capacitor shell with Pushe available. */
export function isPushAvailable(): boolean {
  return bridge() !== null;
}

/** Resolves the Pushe device token (advertising/device id), or null on web. */
export function getDeviceToken(): Promise<string | null> {
  const p = bridge();
  if (!p?.getDeviceId) return Promise.resolve(null);
  return new Promise((resolve) => {
    try {
      p.getDeviceId!((id) => resolve(id || null));
    } catch {
      resolve(null);
    }
  });
}

export function subscribeTopic(topic: string): void {
  bridge()?.subscribe(topic);
}

export function unsubscribeTopic(topic: string): void {
  bridge()?.unsubscribe(topic);
}

/** Marketing / new-café pushes for a city. */
export const cityTopic = (citySlug: string) => `city-${citySlug}`;
/** Saved-café alerts. */
export const cafeTopic = (cafeSlug: string) => `cafe-${cafeSlug}`;

/**
 * Registers this device with the backend so it can receive targeted
 * (order/reservation) pushes and so topic membership is mirrored server-side.
 * No-op on the web.
 */
export async function registerDevice(opts: {
  city?: string;
  savedCafes?: string[];
}): Promise<void> {
  const token = await getDeviceToken();
  if (!token) return;
  try {
    await fetch(`${API_URL}/api/public/push/register`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ token, platform: "android", ...opts }),
    });
  } catch {
    /* best-effort */
  }
}

/**
 * Call once after the user grants notification consent. Initializes Pushe,
 * registers the device, and subscribes to the user's city topic.
 */
export async function enablePush(citySlug?: string): Promise<void> {
  const p = bridge();
  if (!p) return;
  p.setUserConsent?.(true);
  p.initialize?.();
  if (citySlug) subscribeTopic(cityTopic(citySlug));
  await registerDevice({ city: citySlug });
}
