const REPLAY_ROOT = 'q4-user';

function notFound(error) {
  return error?.name === 'NotFoundError' || error?.code === 'ENOENT';
}

async function directory(parent, name, create = true) {
  try {
    return await parent.getDirectoryHandle(name, { create });
  } catch (error) {
    if (!create && notFound(error)) return null;
    throw error;
  }
}

function replayFilename(replay) {
  const id = String(replay?.id || '').replace(/[^A-Za-z0-9_-]/g, '').slice(0, 180);
  if (!id) throw new Error('Powtórka nie ma prawidłowego identyfikatora.');
  return `server-${id}.q4sd`;
}

async function downloadReplay(replay, storage, fetchImpl) {
  if (!storage?.getDirectory || typeof fetchImpl !== 'function') {
    throw new Error('Przeglądarka nie może zapisać powtórki w OPFS.');
  }
  const url = replay.downloadUrl || `/api/replays/${encodeURIComponent(replay.id)}`;
  const response = await fetchImpl(url, { cache: 'no-store' });
  if (!response.ok || !response.body) throw new Error(`Nie udało się pobrać powtórki (HTTP ${response.status}).`);

  const root = await storage.getDirectory();
  const user = await directory(root, REPLAY_ROOT);
  const game = await directory(user, 'baseoq4');
  const demos = await directory(game, 'demos');
  const name = replayFilename(replay);
  const handle = await demos.getFileHandle(name, { create: true });
  const writable = await handle.createWritable();
  const reader = response.body.getReader();
  try {
    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      await writable.write(value);
    }
    await writable.close();
  } catch (error) {
    await reader.cancel(error).catch(() => {});
    await writable.abort?.().catch(() => {});
    throw error;
  }
  return `demos/${name}`;
}

export function createEngineAdapter({
  storage = globalThis.navigator?.storage,
  fetchImpl = globalThis.fetch?.bind(globalThis)
} = {}) {
  let moduleInstance = null;

  function execute(command) {
    if (!moduleInstance) throw new Error('Silnik OpenQ4 nie jest jeszcze gotowy.');
    if (typeof moduleInstance.ccall === 'function') {
      const ok = moduleInstance.ccall('Q4_WebExecuteCommand', 'number', ['string'], [command]);
      if (ok) return true;
    }
    throw new Error('Kompilacja silnika nie udostępnia konsoli przeglądarkowej.');
  }

  return {
    runtimeReady({ module }) {
      moduleInstance = module;
    },
    async playReplay(replay) {
      const relativePath = await downloadReplay(replay, storage, fetchImpl);
      execute(`playServerDemo \"${relativePath}\"`);
    },
    execute
  };
}

export function ensureEngineAdapter(globalObject = globalThis) {
  if (!globalObject.Q4EngineAdapter) globalObject.Q4EngineAdapter = createEngineAdapter();
  return globalObject.Q4EngineAdapter;
}
