// Background fetch task that keeps push alerts flowing when the app is
// backgrounded or killed. OS decides the actual cadence (iOS ~15 min
// minimum, Android is more flexible). On each wake we pull the public
// Delta tickers snapshot, derive spread bps + tick age, and hand the
// data to the shared alerts engine.

import * as TaskManager from "expo-task-manager";
import * as BackgroundFetch from "expo-background-fetch";
import { evaluateAndNotify, TickerLike } from "./alerts";

export const BACKGROUND_ALERTS_TASK = "delta.background-alerts.v1";

// Delta public tickers — no auth required. India endpoint is the primary
// one used by the web app; falling back to the global one keeps the task
// resilient during regional outages.
const ENDPOINTS = [
  "https://api.india.delta.exchange/v2/tickers",
  "https://api.delta.exchange/v2/tickers",
];

interface DeltaTicker {
  symbol: string;
  quotes?: { best_bid?: string; best_ask?: string };
  timestamp?: number; // microseconds
  mark_price?: string;
  turnover_usd?: string;
}

async function fetchTickers(): Promise<TickerLike[]> {
  for (const url of ENDPOINTS) {
    try {
      const res = await fetch(url, { headers: { accept: "application/json" } });
      if (!res.ok) continue;
      const json = (await res.json()) as { result?: DeltaTicker[] };
      const list = json.result ?? [];
      // Rank by turnover to cap notification cost; only the top ~30
      // symbols are checked in the background pass. Per-symbol overrides
      // are always included so a niche coin the user pinned still fires.
      return list
        .filter((t) => t.symbol && (t.symbol.endsWith("USD") || t.symbol.endsWith("USDT")))
        .sort((a, b) => Number(b.turnover_usd ?? 0) - Number(a.turnover_usd ?? 0))
        .slice(0, 30)
        .map<TickerLike>((t) => {
          const bid = Number(t.quotes?.best_bid ?? NaN);
          const ask = Number(t.quotes?.best_ask ?? NaN);
          const mid = Number.isFinite(bid) && Number.isFinite(ask) ? (bid + ask) / 2 : NaN;
          const spread_bps =
            Number.isFinite(bid) && Number.isFinite(ask) && mid > 0
              ? ((ask - bid) / mid) * 10_000
              : null;
          const ts = t.timestamp ? Math.round(t.timestamp / 1000) : Date.now();
          return { symbol: t.symbol, spread_bps, lastUpdate: ts };
        });
    } catch {
      /* try next endpoint */
    }
  }
  return [];
}

TaskManager.defineTask(BACKGROUND_ALERTS_TASK, async () => {
  try {
    const tickers = await fetchTickers();
    if (!tickers.length) return BackgroundFetch.BackgroundFetchResult.NoData;
    const fired = await evaluateAndNotify(tickers);
    return fired > 0
      ? BackgroundFetch.BackgroundFetchResult.NewData
      : BackgroundFetch.BackgroundFetchResult.NoData;
  } catch {
    return BackgroundFetch.BackgroundFetchResult.Failed;
  }
});

export async function registerBackgroundAlerts() {
  try {
    const status = await BackgroundFetch.getStatusAsync();
    if (status === BackgroundFetch.BackgroundFetchStatus.Restricted ||
        status === BackgroundFetch.BackgroundFetchStatus.Denied) {
      return false;
    }
    const already = await TaskManager.isTaskRegisteredAsync(BACKGROUND_ALERTS_TASK);
    if (already) return true;
    await BackgroundFetch.registerTaskAsync(BACKGROUND_ALERTS_TASK, {
      minimumInterval: 15 * 60, // seconds — iOS floor
      stopOnTerminate: false,
      startOnBoot: true,
    });
    return true;
  } catch {
    return false;
  }
}

export async function unregisterBackgroundAlerts() {
  try {
    const already = await TaskManager.isTaskRegisteredAsync(BACKGROUND_ALERTS_TASK);
    if (already) await BackgroundFetch.unregisterTaskAsync(BACKGROUND_ALERTS_TASK);
  } catch {
    /* noop */
  }
}
