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

/**
 * Returns the index of the first occurrence of the needle array in the source
 * array, or -1 if it is not present.
 *
 * A start index can be specified as the third argument that begins the search
 * at that given index. The start index defaults to the start of the array.
 *
 * The complexity of this function is `O(source.length * needle.length)`.
 *
 * @param source Source array to check.
 * @param needle Needle array to check for.
 * @param start Start index in the source array to begin the search. Defaults to
 * 0.
 * @returns Index of the first occurrence of the needle array in the source
 * array, or -1 if it is not present.
 *
 * @example Basic usage
 * ```ts
 * import { indexOfNeedle } from "@std/bytes/index-of-needle";
 *
 * const source = new Uint8Array([0, 1, 2, 1, 2, 1, 2, 3]);
 * const needle = new Uint8Array([1, 2]);
 * const notNeedle = new Uint8Array([5, 0]);
 *
 * indexOfNeedle(source, needle); // 1
 * indexOfNeedle(source, notNeedle); // -1
 * ```
 *
 * @example Start index
 * ```ts
 * import { indexOfNeedle } from "@std/bytes/index-of-needle";
 *
 * const source = new Uint8Array([0, 1, 2, 1, 2, 1, 2, 3]);
 * const needle = new Uint8Array([1, 2]);
 *
 * indexOfNeedle(source, needle, 2); // 3
 * indexOfNeedle(source, needle, 6); // -1
 * ```
 * Defining a start index will begin the search at the specified index in the
 * source array.
 */
export function indexOfNeedle(
  source: Uint8Array,
  needle: Uint8Array,
  start = 0,
): number {
  if (start >= source.length) {
    return -1;
  }
  if (start < 0) {
    start = Math.max(0, source.length + start);
  }
  const s = needle[0];
  for (let i = start; i < source.length; i++) {
    if (source[i] !== s) continue;
    let matched = 1;
    let j = i + 1;
    while (matched < needle.length && source[j] === needle[j - i]) {
      matched++;
      j++;
    }
    if (matched === needle.length) {
      return i;
    }
  }
  return -1;
}

// denoCacheMetadata={"headers":{"date":"Tue, 28 Jul 2026 12:31:14 GMT","x-jsr-backend":"modules","x-robots-tag":"noindex","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';","content-type":"text/typescript","x-content-type-options":"nosniff","set-cookie":"__cf_bm=WkUVvm32UoIYuHgWeQBeQmGKsZDRtbX71FwrQv8j0tQ-1785241874.9461105-1.0.1.1-4Czbs_taF8KlJkydrYLJ3RwP6a9dkz.NIHg7cV8Puc1MnMFf4s.1u0q_5umZ73u5gzwtqv_4.UwrndChKX3caivpJtkG.jUUxYUmTBccoJSI4fJ0hPZz0T.Qkdq0D5Vg; HttpOnly; SameSite=None; Secure; Path=/; Domain=jsr.io; Expires=Tue, 28 Jul 2026 13:01:14 GMT","vary":"Origin","cf-cache-status":"HIT","nel":"{\"report_to\":\"cf-nel\",\"success_fraction\":0.0,\"max_age\":604800}","accept-ranges":"bytes","age":"1455601","access-control-allow-origin":"*","cache-control":"public, max-age=31536000, immutable","cross-origin-resource-policy":"cross-origin","report-to":"{\"group\":\"cf-nel\",\"max_age\":604800,\"endpoints\":[{\"url\":\"https://a.nel.cloudflare.com/report/v4?s=UWUgrq%2BcMLYsgtQ8Z5rtQE8InK6PLKf1m%2FU41HJGZwefrQBzxDABMmy0KCffcFBZRM3dQALY50ZQJ7y1dSqjhQ5B401THhc6mDpk02FEMNpG82%2FkBUZfhRQ%3D\"}]}","server":"cloudflare","alt-svc":"h3=\":443\"; ma=86400","etag":"\"8c229cc77df9859fd7c6ea368fa2f76c\"","access-control-expose-headers":"*","content-length":"2046","cf-ray":"a223e6564ed27db6-LAX"},"url":"https://jsr.io/@std/bytes/0.224.0/index_of_needle.ts","time":1785241874}