// Ported from js-yaml v3.13.1:
// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da
// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license.
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

import { type StyleVariant, Type } from "../type.ts";
import { type Any, isNegativeZero } from "../_utils.ts";

const YAML_FLOAT_PATTERN = new RegExp(
  // 2.5e4, 2.5 and integers
  "^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?" +
    // .2e4, .2
    // special case, seems not from spec
    "|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?" +
    // 20:59
    "|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*" +
    // .inf
    "|[-+]?\\.(?:inf|Inf|INF)" +
    // .nan
    "|\\.(?:nan|NaN|NAN))$",
);

function resolveYamlFloat(data: string): boolean {
  if (
    !YAML_FLOAT_PATTERN.test(data) ||
    // Quick hack to not allow integers end with `_`
    // Probably should update regexp & check speed
    data[data.length - 1] === "_"
  ) {
    return false;
  }

  return true;
}

function constructYamlFloat(data: string): number {
  let value = data.replace(/_/g, "").toLowerCase();
  const sign = value[0] === "-" ? -1 : 1;
  const digits: number[] = [];

  if (value[0] && "+-".indexOf(value[0]) >= 0) {
    value = value.slice(1);
  }

  if (value === ".inf") {
    return sign === 1 ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY;
  }
  if (value === ".nan") {
    return NaN;
  }
  if (value.indexOf(":") >= 0) {
    value.split(":").forEach((v) => {
      digits.unshift(parseFloat(v));
    });

    let valueNb = 0.0;
    let base = 1;

    digits.forEach((d) => {
      valueNb += d * base;
      base *= 60;
    });

    return sign * valueNb;
  }
  return sign * parseFloat(value);
}

const SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/;

function representYamlFloat(object: Any, style?: StyleVariant): Any {
  if (isNaN(object)) {
    switch (style) {
      case "lowercase":
        return ".nan";
      case "uppercase":
        return ".NAN";
      case "camelcase":
        return ".NaN";
    }
  } else if (Number.POSITIVE_INFINITY === object) {
    switch (style) {
      case "lowercase":
        return ".inf";
      case "uppercase":
        return ".INF";
      case "camelcase":
        return ".Inf";
    }
  } else if (Number.NEGATIVE_INFINITY === object) {
    switch (style) {
      case "lowercase":
        return "-.inf";
      case "uppercase":
        return "-.INF";
      case "camelcase":
        return "-.Inf";
    }
  } else if (isNegativeZero(object)) {
    return "-0.0";
  }

  const res = object.toString(10);

  // JS stringifier can build scientific format without dots: 5e-100,
  // while YAML requires dot: 5.e-100. Fix it with simple hack

  return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace("e", ".e") : res;
}

function isFloat(object: Any): boolean {
  return (
    Object.prototype.toString.call(object) === "[object Number]" &&
    (object % 1 !== 0 || isNegativeZero(object))
  );
}

export const float = new Type("tag:yaml.org,2002:float", {
  construct: constructYamlFloat,
  defaultStyle: "lowercase",
  kind: "scalar",
  predicate: isFloat,
  represent: representYamlFloat,
  resolve: resolveYamlFloat,
});

// denoCacheMetadata={"headers":{"vary":"Origin","etag":"\"474326a0f58c924a23534c1622a8e611\"","content-length":"3242","age":"2357727","alt-svc":"h3=\":443\"; ma=86400","cf-ray":"a223e6589ce27db6-LAX","access-control-allow-origin":"*","cf-cache-status":"HIT","cache-control":"public, max-age=31536000, immutable","x-jsr-backend":"modules","date":"Tue, 28 Jul 2026 12:31:15 GMT","content-type":"text/typescript","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';","server":"cloudflare","set-cookie":"__cf_bm=xO2JGuF2CJ639lOU6QzJi5HmKp7hwxI3ZP3_On0eyX8-1785241875.2973816-1.0.1.1-fZ_Vz7lP8Qt5tk81Jk0GSqsmZV8stNrJRk47usZ0yW_uHnT7ea2JHKqg7f4JLZW.T5Ka1KddAe6urqwl3xLDCejXmriG9SND9TlvuqVdbj74ZBhSowFMUIB3.dYGvoc7; HttpOnly; SameSite=None; Secure; Path=/; Domain=jsr.io; Expires=Tue, 28 Jul 2026 13:01:15 GMT","cross-origin-resource-policy":"cross-origin","report-to":"{\"group\":\"cf-nel\",\"max_age\":604800,\"endpoints\":[{\"url\":\"https://a.nel.cloudflare.com/report/v4?s=4Yhv%2F3NiPB53J09GquQOKJaP2wmqHJIYFxQXnmlI3QRvDYYhPHgWMLf4ykufOtRPrRfMdfbF%2FLabQxBvKifKDVG8PRaIGwHlKmIkjidx8xtGgelqyet6qzg%3D\"}]}","x-robots-tag":"noindex","nel":"{\"report_to\":\"cf-nel\",\"success_fraction\":0.0,\"max_age\":604800}","access-control-expose-headers":"*","accept-ranges":"bytes","x-content-type-options":"nosniff"},"url":"https://jsr.io/@std/yaml/0.224.3/_type/float.ts","time":1785241875}