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

import type { Writer, WriterSync } from "./types.ts";

const decoder = new TextDecoder();

/**
 * Writer utility for buffering string chunks.
 *
 * @example Usage
 * ```ts
 * import {
 *   copyN,
 *   StringReader,
 *   StringWriter,
 * } from "@std/io";
 * import { copy } from "@std/io/copy";
 * import { assertEquals } from "@std/assert/equals";
 *
 * const w = new StringWriter("base");
 * const r = new StringReader("0123456789");
 * await copyN(r, w, 4); // copy 4 bytes
 *
 * assertEquals(w.toString(), "base0123");
 *
 * await copy(r, w); // copy all
 * assertEquals(w.toString(), "base0123456789");
 * ```
 *
 * @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 class StringWriter implements Writer, WriterSync {
  #chunks: Uint8Array[] = [];
  #byteLength = 0;
  #cache: string | undefined;
  #base: string;

  /**
   * Construct a new instance.
   *
   * @param base The base string to write to the buffer.
   */
  constructor(base = "") {
    const c = new TextEncoder().encode(base);
    this.#chunks.push(c);
    this.#byteLength += c.byteLength;
    this.#base = base;
  }

  /**
   * Writes the bytes to the buffer asynchronously.
   *
   * @example Usage
   * ```ts
   * import { StringWriter } from "@std/io/string-writer";
   * import { assertEquals } from "@std/assert/equals";
   *
   * const w = new StringWriter("base");
   * await w.write(new TextEncoder().encode("0123"));
   * assertEquals(w.toString(), "base0123");
   * ```
   *
   * @param p The bytes to write to the buffer.
   * @returns The number of bytes written to the buffer in total.
   */
  write(p: Uint8Array): Promise<number> {
    return Promise.resolve(this.writeSync(p));
  }

  /**
   * Writes the bytes to the buffer synchronously.
   *
   * @example Usage
   * ```ts
   * import { StringWriter } from "@std/io/string-writer";
   * import { assertEquals } from "@std/assert/equals";
   *
   * const w = new StringWriter("base");
   * w.writeSync(new TextEncoder().encode("0123"));
   * assertEquals(w.toString(), "base0123");
   * ```
   *
   * @param p The bytes to write to the buffer.
   * @returns The number of bytes written to the buffer in total.
   */
  writeSync(p: Uint8Array): number {
    this.#chunks.push(new Uint8Array(p));
    this.#byteLength += p.byteLength;
    this.#cache = undefined;
    return p.byteLength;
  }

  /**
   * Returns the string written to the buffer.
   *
   * @example Usage
   * ```ts
   * import { StringWriter } from "@std/io/string-writer";
   * import { assertEquals } from "@std/assert/equals";
   *
   * const w = new StringWriter("base");
   * await w.write(new TextEncoder().encode("0123"));
   * assertEquals(w.toString(), "base0123");
   * ```
   *
   * @returns the string written to the buffer.
   */
  toString(): string {
    if (this.#cache) {
      return this.#cache;
    }
    const buf = new Uint8Array(this.#byteLength);
    let offs = 0;
    for (const chunk of this.#chunks) {
      buf.set(chunk, offs);
      offs += chunk.byteLength;
    }
    this.#cache = decoder.decode(buf);
    return this.#cache;
  }
}

// denoCacheMetadata={"headers":{"nel":"{\"report_to\":\"cf-nel\",\"success_fraction\":0.0,\"max_age\":604800}","access-control-expose-headers":"*","set-cookie":"__cf_bm=_ZT2x7UZhcOBEYZJSVaIVasjFqJl1UtK5GamlNx9Xlw-1785241875.0652623-1.0.1.1-3p9TDT20y48pEil0WvczMcxX63OsWjz.A6e8QV0A7F5bPhO98KWn1W0r8qoyedu1CFxiEWwKGtORP7fjsCxgKghl5Bbytgz87cwFro3JlD0PZfiZyrfzFyyOyo71stVz; HttpOnly; SameSite=None; Secure; Path=/; Domain=jsr.io; Expires=Tue, 28 Jul 2026 13:01:15 GMT","report-to":"{\"group\":\"cf-nel\",\"max_age\":604800,\"endpoints\":[{\"url\":\"https://a.nel.cloudflare.com/report/v4?s=IGmGSD2y6yT9KtbufMaCrc3ZqpvkH5WHnlFWZR%2FsMXwfgQqFpcsl3JXIjoc7CX8jCtE2tYSLCkN9wNFWRb%2BjEBbaZ2ZRcdZDqahCxfUmzwmZuy0OuVooJn8%3D\"}]}","server":"cloudflare","access-control-allow-origin":"*","content-type":"text/typescript","content-length":"3292","x-jsr-backend":"modules","cache-control":"public, max-age=31536000, immutable","vary":"Origin","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';","alt-svc":"h3=\":443\"; ma=86400","cross-origin-resource-policy":"cross-origin","etag":"\"d93ec2ebce1d778b4d2236c8c97ec339\"","cf-ray":"a223e65728e37db6-LAX","x-content-type-options":"nosniff","date":"Tue, 28 Jul 2026 12:31:15 GMT"},"url":"https://jsr.io/@std/io/0.224.8/string_writer.ts","time":1785241875}