import { validateDefinitionCollection } from "./site-definitions";
import { saveSettings } from "./settings";
import type { DefinitionCollection, DefinitionSubscription, Settings } from "./types";

export const SUBSCRIPTION_INTERVAL_MS = 7 * 24 * 60 * 60 * 1000;

export interface SubscriptionRefreshResult { settings: Settings; changed: boolean; }

export async function refreshSubscriptions(settings: Settings, fetchImpl: typeof fetch = fetch, now = Date.now()): Promise<SubscriptionRefreshResult> {
  let changed = false;
  const collections = new Map(settings.subscriptionCollections.map((collection) => [collection.collectionId, collection]));
  const subscriptions: DefinitionSubscription[] = [];
  for (const subscription of settings.subscriptions) {
    if (!subscription.enabled) { subscriptions.push(subscription); continue; }
    try {
      const response = await fetchImpl(subscription.url, { headers: { Accept: "application/json" } });
      if (!response.ok) throw new Error(`HTTP ${response.status}`);
      const validation = validateDefinitionCollection(await response.json() as unknown);
      if (!validation.valid) throw new Error(validation.errors.join(" "));
      const collection = validation.value;
      const storedCollection: DefinitionCollection = { ...collection, collectionId: subscription.id };
      const hash = await digest(JSON.stringify(storedCollection));
      changed ||= subscription.lastKnownGoodHash !== hash || !collections.has(subscription.id);
      collections.set(subscription.id, storedCollection);
      subscriptions.push({ ...subscription, lastChecked: new Date(now).toISOString(), lastSuccessfulUpdate: new Date(now).toISOString(), lastKnownGoodHash: hash, lastError: undefined });
    } catch (error) {
      subscriptions.push({ ...subscription, lastChecked: new Date(now).toISOString(), lastError: error instanceof Error ? error.message : String(error) });
    }
  }
  const next = await saveSettings({ subscriptions, subscriptionCollections: [...collections.values()] });
  return { settings: next, changed };
}

export function subscriptionIsDue(subscription: DefinitionSubscription, now = Date.now()): boolean {
  return !subscription.lastSuccessfulUpdate || now - Date.parse(subscription.lastSuccessfulUpdate) >= SUBSCRIPTION_INTERVAL_MS;
}

export function subscriptionsAreDue(settings: Settings, now = Date.now()): boolean {
  return settings.subscriptions.some((subscription) => subscription.enabled && subscriptionIsDue(subscription, now));
}

async function digest(value: string): Promise<string> {
  const bytes = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value));
  return [...new Uint8Array(bytes)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
}
