// Copyright (c) Microsoft Corporation
// Licensed under the MIT license.

import { Module } from "../../../src/ctx.js";

export let module: Module = undefined as any;

// prettier-ignore
const lines = [
  "// Copyright (c) Microsoft Corporation",
  "// Licensed under the MIT license.",
  "",
  "import { Temporal } from \"temporal-polyfill\";",
  "",
  "/**",
  " * Parses an HTTP date string (e.g. `Wed, 21 Oct 2015 07:28:00 GMT`) into a `Temporal.Instant`.",
  " * The date string must be in the format specified by RFC 7231.",
  " *",
  " * @param httpDate - The HTTP date string to parse.",
  " * @throws {RangeError} If the date string is invalid or cannot be parsed.",
  " * @returns The parsed `Temporal.Instant`.",
  " */",
  "export function parseHttpDate(httpDate: string): Temporal.Instant {",
  "  const timestamp = globalThis.Date.parse(httpDate);",
  "",
  "  if (isNaN(timestamp)) {",
  "    throw new RangeError(`Invalid HTTP date: ${httpDate}`);",
  "  }",
  "",
  "  return Temporal.Instant.fromEpochMilliseconds(timestamp);",
  "}",
  "",
  "/**",
  " * Formats a `Temporal.Instant` into an HTTP date string (e.g. `Wed, 21 Oct 2015 07:28:00 GMT`).",
  " * The date string is formatted according to RFC 7231.",
  " *",
  " * @param instant - The `Temporal.Instant` to format.",
  " * @returns The formatted HTTP date string.",
  " */",
  "export function formatHttpDate(instant: Temporal.Instant) {",
  "  const date = new Date(instant.epochMilliseconds);",
  "  return date.toUTCString();",
  "}",
  "",
  "/**",
  " * Converts a `Temporal.Duration` to a number of seconds.",
  " * This method will throw an Error if the duration contains any years, months, weeks, or days, as those require a reference",
  " * point to calculate the total number of seconds.",
  " *",
  " * WARNING: If the total number of seconds is larger than the maximum safe integer in JavaScript, this method will",
  " * lose precision. @see durationTotalSecondsBigInt for a BigInt alternative.",
  " *",
  " * @param duration - the duration to calculate the total number of seconds for",
  " * @returns the total number of seconds in the duration",
  " */",
  "export function durationTotalSeconds(duration: Temporal.Duration): number {",
  "  if (",
  "    duration.years !== 0 ||",
  "    duration.months !== 0 ||",
  "    duration.weeks !== 0 ||",
  "    duration.days !== 0",
  "  ) {",
  "    throw new Error(",
  "      \"Cannot calculate total seconds for a duration with years, months, weeks, or days.\",",
  "    );",
  "  }",
  "",
  "  return (",
  "    duration.seconds +",
  "    duration.minutes * 60 +",
  "    duration.hours * 60 * 60 +",
  "    duration.days * 24 * 60 * 60",
  "  );",
  "}",
  "",
  "/**",
  " * Gets the total number of seconds in a duration.",
  " *",
  " * This method will throw an Error if the duration contains any years, months, weeks, or days, as those require a reference",
  " * point to calculate the total number of seconds. It will also throw an error if any of the components are not integers.",
  " *",
  " * @param duration - the duration to calculate the total number of seconds for",
  " * @returns the total number of seconds in the duration",
  " */",
  "export function durationTotalSecondsBigInt(duration: Temporal.Duration): bigint {",
  "  if (",
  "    duration.years !== 0 ||",
  "    duration.months !== 0 ||",
  "    duration.weeks !== 0 ||",
  "    duration.days !== 0",
  "  ) {",
  "    throw new Error(",
  "      \"Cannot calculate total seconds for a duration with years, months, weeks, or days.\",",
  "    );",
  "  }",
  "",
  "  if (",
  "    !Number.isInteger(duration.seconds) ||",
  "    !Number.isInteger(duration.minutes) ||",
  "    !Number.isInteger(duration.hours) ||",
  "    !Number.isInteger(duration.days)",
  "  ) {",
  "    throw new Error(\"Duration components must be integers.\");",
  "  }",
  "",
  "  return (",
  "    BigInt(duration.seconds) +",
  "    BigInt(duration.minutes) * 60n +",
  "    BigInt(duration.hours) * 60n * 60n +",
  "    BigInt(duration.days) * 24n * 60n * 60n",
  "  );",
  "}",
  "",
];

export async function createModule(parent: Module): Promise<Module> {
  if (module) return module;

  module = {
    name: "polyfill",
    cursor: parent.cursor.enter("polyfill"),
    imports: [],
    declarations: [],
  };

  module.declarations.push(lines);

  parent.declarations.push(module);

  return module;
}
