/*--------------------------------------------------------------------------

TypeBox

The MIT License (MIT)

Copyright (c) 2017-2026 Haydn Paterson

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

---------------------------------------------------------------------------*/

import { Guard } from '../../guard/index.ts'

// ------------------------------------------------------------------
// Settings
// ------------------------------------------------------------------

export interface TSettings {
  /**
   * Determines whether types should be instantiated as immutable using `Object.freeze(...)`.
   * This helps prevent unintended schema mutation. Enabling this option introduces a slight
   * performance overhead during instantiation.
   *
   * @default false
   */
  immutableTypes: boolean

  /**
   * Specifies the maximum number of errors to buffer during diagnostics collection. TypeBox
   * performs exhaustive checks to gather diagnostics for invalid values, which can result in
   * excessive buffering for large or complex types. This setting limits the number of buffered
   * errors and acts as a safeguard against potential denial-of-service (DoS) attacks.
   *
   * @default 8
   */
  maxErrors: number

  /**
   * Specifies the maximum number of instantiations allowed within a top-level generic instantiation
   * context. This setting can be used to bound generic calls to a fixed count, which can be useful if
   * evaluating string-encoded types originating from untrusted sources. Setting this value to 0 will
   * disallow generics entirely, ensuring type instantiation runs linear.
   *
   * @default 128
   */
  maxInstantiationCount: number

  /**
   * Enables or disables the use of runtime code evaluation to accelerate validation. By default,
   * TypeBox checks for `unsafe-eval` support in the environment before attempting to evaluate
   * generated code. If evaluation is not permitted, it falls back to dynamic checking. Setting
   * this to `false` disables evaluation entirely, which may be desirable in applications that
   * restrict runtime code evaluation, regardless of Content Security Policy (CSP).
   *
   * @default true
   */
  useAcceleration: boolean

  /**
   * Enables or disables 'exactOptionalPropertyTypes' check semantics. By default, TypeScript
   * allows optional properties to be assigned 'undefined'. While this behavior differs from the
   * common interpretation of 'optional' as meaning 'key may be absent', TypeBox adopts the default
   * TypeScript semantics to remain consistent with the language. This option is provided to align
   * runtime check semantics with projects that configure 'exactOptionalPropertyTypes: true' in
   * tsconfig.json.
   *
   * @default false
   */
  exactOptionalPropertyTypes: boolean

  /**
   * Controls whether internal compositor properties (`~kind`, `~readonly`, `~optional`) are enumerable.
   *
   * @default false
   */
  enumerableKind: boolean

  /**
   * Controls whether TypeBox uses corrective Parse. When enabled, TypeBox will attempt to recover invalid
   * values during Parse by running a sequence of `Value.*` operations to `Convert`, `Default`, and `Clean`
   * the value, followed by a subsequent `Assert`. Enabling this option may incur significant performance
   * overhead for invalid values. It is recommended to keep this disabled in performance-sensitive
   * applications.
   *
   * @default false
   */
  correctiveParse: boolean

  /**
   * Controls whether TypeBox sorts Union variants by specificity (narrowest first) for operations
   * that require deterministic value matching, such as Clean, Decode, and Encode. When enabled,
   * more specific types (e.g. Literal) always take precedence over broader types (e.g. String),
   * regardless of the order variants are declared.
   *
   * @default true
   */
  unionPrioritySort: boolean
}

// Internal mutable state
const settings: TSettings = {
  immutableTypes: false,
  maxErrors: 8,
  maxInstantiationCount: 128,
  useAcceleration: true,
  exactOptionalPropertyTypes: false,
  enumerableKind: false,
  correctiveParse: false,
  unionPrioritySort: true
}

/** Resets system settings to defaults */
export function Reset(): void {
  settings.immutableTypes = false
  settings.maxErrors = 8
  settings.maxInstantiationCount = 128
  settings.useAcceleration = true
  settings.exactOptionalPropertyTypes = false
  settings.enumerableKind = false
  settings.correctiveParse = false
  settings.unionPrioritySort = true
}

/** Sets system settings */
export function Set(options: Partial<TSettings>): void {
  for (const key of Guard.Keys(options)) {
    const value = options[key as keyof TSettings]
    if (value !== undefined) {
      Object.defineProperty(settings, key, { value })
    }
  }
}

/** Gets current system settings */
export function Get(): Readonly<TSettings> {
  return settings
}
