import { fileApi } from "./fileApi";
import { parseContentDispositionFilename } from "./filename";

interface PreviewRequest {
  controller: AbortController;
  promise: Promise<Awaited<ReturnType<typeof fileApi.preview>>>;
  consumers: number;
}
const previewRequests = new Map<string, PreviewRequest>();
const previewResults = new Map<string, Awaited<ReturnType<typeof fileApi.preview>>>();

function previewKey(id: string, version: string | number = ""): string {
  return `${id}:${version}`;
}

export function loadPreviewOnce(id: string, version: string | number = "") {
  const key = previewKey(id, version);
  const cached = previewResults.get(key);
  if (cached) return Promise.resolve(cached);
  const existing = previewRequests.get(key);
  if (existing) return existing.promise;
  const controller = new AbortController();
  const request: PreviewRequest = {
    controller,
    consumers: 0,
    promise: Promise.resolve(undefined as never),
  };
  request.promise = fileApi.preview(id, controller.signal)
    .then((result) => {
      previewResults.set(key, result);
      return result;
    })
    .finally(() => {
      if (previewRequests.get(key) === request) previewRequests.delete(key);
    });
  previewRequests.set(key, request);
  return request.promise;
}

export function acquirePreview(id: string, version: string | number = ""): {
  promise: Promise<Awaited<ReturnType<typeof fileApi.preview>>>;
  release: () => void;
} {
  const key = previewKey(id, version);
  const promise = loadPreviewOnce(id, version);
  const request = previewRequests.get(key);
  if (!request) return { promise, release: () => undefined };
  request.consumers += 1;
  let released = false;
  return {
    promise,
    release: () => {
      if (released) return;
      released = true;
      request.consumers -= 1;
      globalThis.setTimeout(() => {
        if (
          request.consumers === 0 &&
          previewRequests.get(key) === request
        ) {
          request.controller.abort();
          previewRequests.delete(key);
        }
      }, 0);
    },
  };
}

export function createPreviewUrl(blob: Blob): string {
  return URL.createObjectURL(blob);
}

export function revokeObjectUrl(url: string | null): void {
  if (url) URL.revokeObjectURL(url);
}

export async function downloadFile(
  id: string,
  fallbackName: string,
  signal?: AbortSignal,
): Promise<{ filename: string; requestId: string }> {
  const result = await fileApi.download(id, signal);
  const filename = parseContentDispositionFilename(
    result.contentDisposition,
    fallbackName,
  );
  const url = URL.createObjectURL(result.blob);
  const anchor = document.createElement("a");
  try {
    anchor.href = url;
    anchor.download = filename;
    anchor.style.display = "none";
    document.body.appendChild(anchor);
    anchor.click();
  } finally {
    anchor.remove();
    URL.revokeObjectURL(url);
  }
  return { filename, requestId: result.requestId };
}

export function clearPreviewRequestsForTests(): void {
  previewRequests.clear();
  previewResults.clear();
}

export function invalidatePreview(id: string): void {
  for (const key of previewResults.keys()) {
    if (key.startsWith(`${id}:`)) previewResults.delete(key);
  }
}
