import { useEffect, useState } from "react";
import {
  APP_VERSION,
  compareVersions,
  fetchAppInfo,
  resolveInstalledVersion,
  type AppInfo,
} from "@/lib/appInfo";

export type UpdateState = {
  loading: boolean;
  /** Backend payload (creator, support, privacy too — not just update). */
  info: AppInfo | null;
  /**
   * Installed version. On Android/iOS this is the native APK `versionName`
   * (build.gradle), so users automatically stop seeing the popup once they
   * install the new APK — no rebuild of the JS bundle required.
   */
  installedVersion: string;
  /** True when admin enabled the feature AND latest > installed. */
  hasUpdate: boolean;
  /**
   * True when installed < min_supported_version → the popup must block all UI
   * (no "Later" button). When false but `hasUpdate` is true, the popup is
   * dismissible.
   */
  forced: boolean;
};

const POLL_INTERVAL_MS = 5 * 60 * 1000; // refresh every 5 minutes
const SNOOZE_KEY = "nadi_update_snoozed_for"; // value = the version snoozed

/** Returns app-info + computed update flags. Polls in the background. */
export function useAppUpdate(): UpdateState {
  const [info, setInfo] = useState<AppInfo | null>(null);
  const [loading, setLoading] = useState(true);
  // Resolve once on mount. Web fallback returns the bundle's APP_VERSION
  // synchronously enough that this is a single repaint.
  const [installedVersion, setInstalledVersion] = useState<string>(APP_VERSION);

  useEffect(() => {
    let cancelled = false;
    void resolveInstalledVersion().then((v) => {
      if (!cancelled) setInstalledVersion(v);
    });
    return () => { cancelled = true; };
  }, []);

  useEffect(() => {
    let cancelled = false;

    const tick = async () => {
      try {
        const data = await fetchAppInfo();
        if (!cancelled) setInfo(data);
        // Mirror the admin's player_notice_enabled choice into the cache
        // the ExternalPlayerNotice reads. Gives us a second channel so the
        // popup respects the admin even if /api/public/playback-mode is
        // stale on a particular host.
        try {
          const flag = data?.flags?.player_notice_enabled;
          if (typeof flag === "boolean") {
            localStorage.setItem(
              "nadiplay.playerNotice.enabledCache.v1",
              flag ? "1" : "0",
            );
          }
        } catch { /* ignore */ }
      } catch {
        // network errors are non-fatal — popup just doesn't show
      } finally {
        if (!cancelled) setLoading(false);
      }
    };

    void tick();
    const timer = setInterval(tick, POLL_INTERVAL_MS);
    return () => {
      cancelled = true;
      clearInterval(timer);
    };
  }, []);

  const u = info?.update;
  const enabled = !!u?.enabled;
  const hasUpdate =
    enabled &&
    !!u?.latest_version &&
    compareVersions(u.latest_version, installedVersion) > 0;
  const forced =
    enabled &&
    !!u?.min_supported_version &&
    compareVersions(installedVersion, u.min_supported_version) < 0;

  return {
    loading,
    info,
    installedVersion,
    hasUpdate,
    forced,
  };
}

/** Snooze a non-forced update for the current session (per-version). */
export function snoozeUpdate(version: string) {
  try {
    sessionStorage.setItem(SNOOZE_KEY, version || "");
  } catch {
    /* ignore */
  }
}

export function isSnoozed(version: string): boolean {
  try {
    return sessionStorage.getItem(SNOOZE_KEY) === (version || "");
  } catch {
    return false;
  }
}
