import type { CursorFetchRequest, CursorPageResponse } from "./cursorFetchCore";
import { fetchAllCursorPagesMainThread } from "./cursorFetchCore";

type CursorWorkerResponseMessage<TItem> =
  | {
      id: string;
      ok: true;
      response: CursorPageResponse<TItem>;
    }
  | {
      id: string;
      ok: false;
      error: string;
    };

function createRequestId() {
  if (globalThis.crypto?.randomUUID) {
    return globalThis.crypto.randomUUID();
  }
  return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
}

function shouldUseWorker(useWorker: boolean | undefined) {
  if (useWorker === false || typeof Worker === "undefined") {
    return false;
  }

  const maybeWindow = globalThis as typeof globalThis & {
    window?: Window & typeof globalThis & { _IS_TEST_MODE?: boolean };
  };
  return maybeWindow.window?._IS_TEST_MODE !== true;
}

async function fetchAllCursorPagesInWorker<TItem>(
  request: CursorFetchRequest,
): Promise<CursorPageResponse<TItem>> {
  const worker = new Worker(
    new URL("./cursorFetch.worker.ts", import.meta.url),
    {
      type: "module",
    },
  );
  const id = createRequestId();

  return new Promise((resolve, reject) => {
    worker.onmessage = (
      event: MessageEvent<CursorWorkerResponseMessage<TItem>>,
    ) => {
      if (event.data.id !== id) {
        return;
      }
      worker.terminate();

      if (event.data.ok) {
        resolve(event.data.response);
      } else {
        reject(new Error(event.data.error));
      }
    };

    worker.onerror = (event) => {
      worker.terminate();
      reject(new Error(event.message || "Cursor worker failed"));
    };

    worker.postMessage({ id, request });
  });
}

export async function fetchAllCursorPages<TItem>(
  request: CursorFetchRequest & { useWorker?: boolean },
): Promise<CursorPageResponse<TItem>> {
  if (shouldUseWorker(request.useWorker)) {
    try {
      return await fetchAllCursorPagesInWorker<TItem>(request);
    } catch {
      return fetchAllCursorPagesMainThread<TItem>(request);
    }
  }

  return fetchAllCursorPagesMainThread<TItem>(request);
}

export type { CursorFetchRequest, CursorPageResponse } from "./cursorFetchCore";
export { fetchAllCursorPagesMainThread } from "./cursorFetchCore";
