// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// This module is browser compatible.

import { concat } from "jsr:@std/bytes@^1.0.2/concat";
import type { Reader } from "./types.ts";

/** Generate longest proper prefix which is also suffix array. */
function createLPS(pat: Uint8Array): Uint8Array {
  const lps = new Uint8Array(pat.length);
  lps[0] = 0;
  let prefixEnd = 0;
  let i = 1;
  while (i < lps.length) {
    if (pat[i] === pat[prefixEnd]) {
      prefixEnd++;
      lps[i] = prefixEnd;
      i++;
    } else if (prefixEnd === 0) {
      lps[i] = 0;
      i++;
    } else {
      prefixEnd = lps[prefixEnd - 1]!;
    }
  }
  return lps;
}

/**
 * Read delimited bytes from a {@linkcode Reader} through an
 * {@linkcode AsyncIterableIterator} of {@linkcode Uint8Array}.
 *
 * @example Usage
 * ```ts
 * import { readDelim } from "@std/io/read-delim";
 * import { assert } from "@std/assert/assert"
 *
 * const fileReader = await Deno.open("README.md");
 * for await (const chunk of readDelim(fileReader, new TextEncoder().encode("\n"))) {
 *   assert(chunk instanceof Uint8Array);
 * }
 * ```
 *
 * @param reader The reader to read from
 * @param delim The delimiter to read until
 * @returns The {@linkcode AsyncIterableIterator} of {@linkcode Uint8Array}s.
 *
 * @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
 */
export async function* readDelim(
  reader: Reader,
  delim: Uint8Array,
): AsyncIterableIterator<Uint8Array> {
  // Avoid unicode problems
  const delimLen = delim.length;
  const delimLPS = createLPS(delim);
  let chunks = new Uint8Array();
  const bufSize = Math.max(1024, delimLen + 1);

  // Modified KMP
  let inspectIndex = 0;
  let matchIndex = 0;
  while (true) {
    const inspectArr = new Uint8Array(bufSize);
    const result = await reader.read(inspectArr);
    if (result === null) {
      // Yield last chunk.
      yield chunks;
      return;
    } else if (result < 0) {
      // Discard all remaining and silently fail.
      return;
    }
    chunks = concat([chunks, inspectArr.slice(0, result)]);
    let localIndex = 0;
    while (inspectIndex < chunks.length) {
      if (inspectArr[localIndex] === delim[matchIndex]) {
        inspectIndex++;
        localIndex++;
        matchIndex++;
        if (matchIndex === delimLen) {
          // Full match
          const matchEnd = inspectIndex - delimLen;
          const readyBytes = chunks.slice(0, matchEnd);
          yield readyBytes;
          // Reset match, different from KMP.
          chunks = chunks.slice(inspectIndex);
          inspectIndex = 0;
          matchIndex = 0;
        }
      } else {
        if (matchIndex === 0) {
          inspectIndex++;
          localIndex++;
        } else {
          matchIndex = delimLPS[matchIndex - 1]!;
        }
      }
    }
  }
}

// denoCacheMetadata={"headers":{"nel":"{\"report_to\":\"cf-nel\",\"success_fraction\":0.0,\"max_age\":604800}","content-security-policy":"default-src 'none'; script-src 'none'; style-src 'none'; img-src 'none'; font-src 'none'; connect-src 'none'; frame-src 'none'; object-src 'none'; frame-ancestors 'none'; sandbox; form-action 'none';","cache-control":"public, max-age=31536000, immutable","x-robots-tag":"noindex","alt-svc":"h3=\":443\"; ma=86400","content-length":"2916","access-control-allow-origin":"*","report-to":"{\"group\":\"cf-nel\",\"max_age\":604800,\"endpoints\":[{\"url\":\"https://a.nel.cloudflare.com/report/v4?s=G3Djj37NhNR6g35yElZzZe3CTk5yakflBpbrOHswzOorKzJfmgai6HG7Nad8EQZSbFvRY2b6tIzzUAnuhbJezE2nQhxTwtDV5apOVehv3kKWMJOcKlgZZ7g%3D\"}]}","date":"Tue, 28 Jul 2026 12:31:15 GMT","content-type":"text/typescript","cross-origin-resource-policy":"cross-origin","x-jsr-backend":"modules","server":"cloudflare","cf-ray":"a223e656f86b7db6-LAX","vary":"Origin","access-control-expose-headers":"*","x-content-type-options":"nosniff","etag":"\"f488002f9ad839f1c6b67253d113d81b\"","set-cookie":"__cf_bm=ApTqM1m_31SN2lF67cx6rTkopUalOOFY3wwTV96CPwQ-1785241875.0340207-1.0.1.1-g9Eggc3Rg9TnAm0i7GMJ_7ZyLexWKw1gakXolmY9AXyVm6yqXUzA2ZHP8omJ._TmDJz1e6vZIrN3wD82soabNHQFYzomxbNfQUklHWZ8B6c7yflZOtDSQ2yPqq_kWfLr; HttpOnly; SameSite=None; Secure; Path=/; Domain=jsr.io; Expires=Tue, 28 Jul 2026 13:01:15 GMT"},"url":"https://jsr.io/@std/io/0.224.8/read_delim.ts","time":1785241875}