import { get, writable } from 'svelte/store';
import { ApiError, getAccountData, getUrlPreview, setAccountData } from './api';
import { parseLinkPreview } from './types';
import type { LinkPreview } from './types';

const EVENT_TYPE = 'dev.malice.url_previews';
const BACKOFF_MS = 30_000;

export interface UrlPreviewSettings {
  encrypted_rooms: boolean;
}

const DEFAULT_SETTINGS: UrlPreviewSettings = { encrypted_rooms: false };

export const linkPreviews = writable<Record<string, LinkPreview | null>>({});
export const urlPreviewSettings = writable<UrlPreviewSettings>(DEFAULT_SETTINGS);

const inFlight = new Set<string>();
let backoffUntil = 0;

export function requestLinkPreview(roomId: string, url: string): void {
  if (inFlight.has(url) || url in get(linkPreviews) || Date.now() < backoffUntil) return;
  inFlight.add(url);
  getUrlPreview(roomId, url)
    .then((raw) => linkPreviews.update((all) => ({ ...all, [url]: parseLinkPreview(raw) })))
    .catch((e) => {
      if (e instanceof ApiError && e.status === 429) backoffUntil = Date.now() + BACKOFF_MS;
    })
    .finally(() => inFlight.delete(url));
}

function parseSettings(raw: unknown): UrlPreviewSettings {
  if (typeof raw !== 'object' || raw === null) return DEFAULT_SETTINGS;
  return { encrypted_rooms: (raw as Record<string, unknown>)['encrypted_rooms'] === true };
}

export async function loadUrlPreviewSettings(): Promise<void> {
  try {
    urlPreviewSettings.set(parseSettings(await getAccountData(EVENT_TYPE)));
  } catch {
    urlPreviewSettings.set(DEFAULT_SETTINGS);
  }
}

export async function saveUrlPreviewSettings(settings: UrlPreviewSettings): Promise<void> {
  await setAccountData(EVENT_TYPE, { encrypted_rooms: settings.encrypted_rooms });
  urlPreviewSettings.set(settings);
}

export function resetLinkPreviews(): void {
  linkPreviews.set({});
  urlPreviewSettings.set(DEFAULT_SETTINGS);
  inFlight.clear();
  backoffUntil = 0;
}
