// 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.
// This module is browser compatible.

import type { KindType, Type } from "./_type.ts";
import { binary } from "./_type/binary.ts";
import { bool } from "./_type/bool.ts";
import { float } from "./_type/float.ts";
import { int } from "./_type/int.ts";
import { map } from "./_type/map.ts";
import { merge } from "./_type/merge.ts";
import { nil } from "./_type/nil.ts";
import { omap } from "./_type/omap.ts";
import { pairs } from "./_type/pairs.ts";
import { regexp } from "./_type/regexp.ts";
import { seq } from "./_type/seq.ts";
import { set } from "./_type/set.ts";
import { str } from "./_type/str.ts";
import { timestamp } from "./_type/timestamp.ts";
import { undefinedType } from "./_type/undefined.ts";

/**
 * Name of the schema to use.
 *
 * > [!NOTE]
 * > It is recommended to use the schema that is most appropriate for your use
 * > case. Doing so will avoid any unnecessary processing and benefit
 * > performance.
 *
 * Options include:
 * - `failsafe`: supports generic mappings, generic sequences and generic
 * strings.
 * - `json`: extends `failsafe` schema by also supporting nulls, booleans,
 * integers and floats.
 * - `core`: functionally the same as `json` schema.
 * - `default`: extends `core` schema by also supporting binary, omap, pairs and
 * set types.
 * - `extended`: extends `default` schema by also supporting regular
 * expressions and undefined values.
 *
 * See
 * {@link https://yaml.org/spec/1.2.2/#chapter-10-recommended-schemas | YAML 1.2 spec}
 * for more details on the `failsafe`, `json` and `core` schemas.
 */
export type SchemaType = "failsafe" | "json" | "core" | "default" | "extended";

type ImplicitType = Type<"scalar">;
type ExplicitType = Type<KindType>;

export type TypeMap = Record<
  KindType | "fallback",
  Map<string, ExplicitType>
>;

function createTypeMap(
  implicitTypes: ImplicitType[],
  explicitTypes: ExplicitType[],
): TypeMap {
  const result: TypeMap = {
    fallback: new Map(),
    mapping: new Map(),
    scalar: new Map(),
    sequence: new Map(),
  };
  const fallbackMap = result.fallback;
  for (const type of [...implicitTypes, ...explicitTypes]) {
    const map = result[type.kind];
    map.set(type.tag, type);
    fallbackMap.set(type.tag, type);
  }
  return result;
}

export interface Schema {
  implicitTypes: ImplicitType[];
  explicitTypes: ExplicitType[];
  typeMap: TypeMap;
}

function createSchema({ explicitTypes = [], implicitTypes = [], include }: {
  implicitTypes?: ImplicitType[];
  explicitTypes?: ExplicitType[];
  include?: Schema;
}): Schema {
  if (include) {
    implicitTypes.push(...include.implicitTypes);
    explicitTypes.push(...include.explicitTypes);
  }
  const typeMap = createTypeMap(implicitTypes, explicitTypes);
  return { implicitTypes, explicitTypes, typeMap };
}

/**
 * Standard YAML's failsafe schema.
 *
 * @see {@link http://www.yaml.org/spec/1.2/spec.html#id2802346}
 */
const FAILSAFE_SCHEMA = createSchema({
  explicitTypes: [str, seq, map],
});

/**
 * Standard YAML's JSON schema.
 *
 * @see {@link http://www.yaml.org/spec/1.2/spec.html#id2803231}
 */
const JSON_SCHEMA = createSchema({
  implicitTypes: [nil, bool, int, float],
  include: FAILSAFE_SCHEMA,
});

/**
 * Standard YAML's core schema.
 *
 * @see {@link http://www.yaml.org/spec/1.2/spec.html#id2804923}
 */
const CORE_SCHEMA = createSchema({
  include: JSON_SCHEMA,
});

/**
 * Default YAML schema. It is not described in the YAML specification.
 */
export const DEFAULT_SCHEMA = createSchema({
  explicitTypes: [binary, omap, pairs, set],
  implicitTypes: [timestamp, merge],
  include: CORE_SCHEMA,
});

/***
 * Extends JS-YAML default schema with additional JavaScript types
 * It is not described in the YAML specification.
 * Functions are no longer supported for security reasons.
 *
 * @example
 * ```ts
 * import { parse } from "@std/yaml";
 *
 * const data = parse(
 *   `
 *   regexp:
 *     simple: !!js/regexp foobar
 *     modifiers: !!js/regexp /foobar/mi
 *   undefined: !!js/undefined ~
 * # Disabled, see: https://github.com/denoland/deno_std/pull/1275
 * #  function: !!js/function >
 * #    function foobar() {
 * #      return 'hello world!';
 * #    }
 * `,
 *   { schema: "extended" },
 * );
 * ```
 */
const EXTENDED_SCHEMA = createSchema({
  explicitTypes: [regexp, undefinedType],
  include: DEFAULT_SCHEMA,
});

export const SCHEMA_MAP = new Map<SchemaType, Schema>([
  ["core", CORE_SCHEMA],
  ["default", DEFAULT_SCHEMA],
  ["failsafe", FAILSAFE_SCHEMA],
  ["json", JSON_SCHEMA],
  ["extended", EXTENDED_SCHEMA],
]);

// denoCacheMetadata={"headers":{"vary":"Origin","accept-ranges":"bytes","server":"cloudflare","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';","x-jsr-backend":"modules","age":"1630862","report-to":"{\"group\":\"cf-nel\",\"max_age\":604800,\"endpoints\":[{\"url\":\"https://a.nel.cloudflare.com/report/v4?s=2pntedS%2Bd0Q285x5yN7SMSaEVvlM8VANTHkJgojA0UBVIxg47xfrJuVFg9ZyWvfrtDo04pCx1bYEX1Yr58HLQUW5Ezo7aOfRNe9EFdRp0iwO4gNtiuAO3hA%3D\"}]}","cross-origin-resource-policy":"cross-origin","access-control-expose-headers":"*","set-cookie":"__cf_bm=C.coytOVVlPsCxOZq6lTAE3Sys4FI7vwaRLd6Q5Yy3A-1785241875.3377752-1.0.1.1-_xzD5JOzpOR1VbDze57O7OlX.NHxw5enG3X58nbIrmQQ478LRG373_s9DgIOK0WWmvlWQp.In3y3h2nRhqebn58TpBTen8LJK4VZhBvFdVNjWXS1r4hl5x6JLSsdhqyL; HttpOnly; SameSite=None; Secure; Path=/; Domain=jsr.io; Expires=Tue, 28 Jul 2026 13:01:15 GMT","access-control-allow-origin":"*","alt-svc":"h3=\":443\"; ma=86400","cf-cache-status":"HIT","cache-control":"public, max-age=31536000, immutable","nel":"{\"report_to\":\"cf-nel\",\"success_fraction\":0.0,\"max_age\":604800}","date":"Tue, 28 Jul 2026 12:31:15 GMT","content-type":"text/typescript","x-content-type-options":"nosniff","content-length":"4814","x-robots-tag":"noindex","cf-ray":"a223e658cda07db6-LAX","etag":"\"eb36632b32dfadb1d100a28fc09352c1\""},"url":"https://jsr.io/@std/yaml/1.0.5/_schema.ts","time":1785241875}