/*
This file was derived from the TypeScript project.
Original source: https://github.com/microsoft/TypeScript/blob/main/src/lib/esnext.intl.d.ts
Copyright (c) Microsoft Corporation. Licensed under the Apache License 2.0.
*/

/// <reference lib="es2015.symbol.wellknown" />
/// <reference lib="es2020.intl" />
/// <reference lib="es2021.intl" />

export {} // treat as a module

declare global {
  namespace Temporal {
    type CalendarLike =
      | PlainDate
      | PlainDateTime
      | PlainMonthDay
      | PlainYearMonth
      | ZonedDateTime
      | string
    type DurationLike = Duration | DurationLikeObject | string
    type InstantLike = Instant | ZonedDateTime | string
    type PlainDateLike =
      | PlainDate
      | ZonedDateTime
      | PlainDateTime
      | DateLikeObject
      | string
    type PlainDateTimeLike =
      | PlainDateTime
      | ZonedDateTime
      | PlainDate
      | DateTimeLikeObject
      | string
    type PlainMonthDayLike = PlainMonthDay | DateLikeObject | string
    type PlainTimeLike =
      | PlainTime
      | PlainDateTime
      | ZonedDateTime
      | TimeLikeObject
      | string
    type PlainYearMonthLike = PlainYearMonth | YearMonthLikeObject | string
    type TimeZoneLike = ZonedDateTime | string
    type ZonedDateTimeLike = ZonedDateTime | ZonedDateTimeLikeObject | string

    type PartialTemporalLike<T extends object> = {
      [P in Exclude<keyof T, 'calendar' | 'timeZone'>]?: T[P] | undefined
    }

    interface DateLikeObject {
      year?: number | undefined
      era?: string | undefined
      eraYear?: number | undefined
      month?: number | undefined
      monthCode?: string | undefined
      day: number
      calendar?: string | undefined
    }

    interface DateTimeLikeObject extends DateLikeObject, TimeLikeObject {}

    interface DurationLikeObject {
      years?: number | undefined
      months?: number | undefined
      weeks?: number | undefined
      days?: number | undefined
      hours?: number | undefined
      minutes?: number | undefined
      seconds?: number | undefined
      milliseconds?: number | undefined
      microseconds?: number | undefined
      nanoseconds?: number | undefined
    }

    interface TimeLikeObject {
      hour?: number | undefined
      minute?: number | undefined
      second?: number | undefined
      millisecond?: number | undefined
      microsecond?: number | undefined
      nanosecond?: number | undefined
    }

    interface YearMonthLikeObject extends Omit<DateLikeObject, 'day'> {}

    interface ZonedDateTimeLikeObject extends DateTimeLikeObject {
      timeZone: TimeZoneLike
      offset?: string | undefined
    }

    type DateUnit = 'year' | 'month' | 'week' | 'day'
    type TimeUnit =
      | 'hour'
      | 'minute'
      | 'second'
      | 'millisecond'
      | 'microsecond'
      | 'nanosecond'
    type PluralizeUnit<T extends DateUnit | TimeUnit> =
      | T
      | {
          year: 'years'
          month: 'months'
          week: 'weeks'
          day: 'days'
          hour: 'hours'
          minute: 'minutes'
          second: 'seconds'
          millisecond: 'milliseconds'
          microsecond: 'microseconds'
          nanosecond: 'nanoseconds'
        }[T]

    interface DisambiguationOptions {
      disambiguation?: 'compatible' | 'earlier' | 'later' | 'reject' | undefined
    }

    interface OverflowOptions {
      overflow?: 'constrain' | 'reject' | undefined
    }

    interface TransitionOptions {
      direction: 'next' | 'previous'
    }

    interface RoundingOptions<Units extends DateUnit | TimeUnit> {
      smallestUnit?: PluralizeUnit<Units> | undefined
      roundingIncrement?: number | undefined
      roundingMode?:
        | 'ceil'
        | 'floor'
        | 'expand'
        | 'trunc'
        | 'halfCeil'
        | 'halfFloor'
        | 'halfExpand'
        | 'halfTrunc'
        | 'halfEven'
        | undefined
    }

    interface RoundingOptionsWithLargestUnit<Units extends DateUnit | TimeUnit>
      extends RoundingOptions<Units> {
      largestUnit?: 'auto' | PluralizeUnit<Units> | undefined
    }

    interface ToStringRoundingOptions<Units extends DateUnit | TimeUnit>
      extends Pick<RoundingOptions<Units>, 'smallestUnit' | 'roundingMode'> {}

    interface ToStringRoundingOptionsWithFractionalSeconds<
      Units extends DateUnit | TimeUnit,
    > extends ToStringRoundingOptions<Units> {
      fractionalSecondDigits?:
        | 'auto'
        | 0
        | 1
        | 2
        | 3
        | 4
        | 5
        | 6
        | 7
        | 8
        | 9
        | undefined
    }

    namespace Now {
      function timeZoneId(): string
      function instant(): Instant
      function plainDateTimeISO(timeZone?: TimeZoneLike): PlainDateTime
      function zonedDateTimeISO(timeZone?: TimeZoneLike): ZonedDateTime
      function plainDateISO(timeZone?: TimeZoneLike): PlainDate
      function plainTimeISO(timeZone?: TimeZoneLike): PlainTime
    }

    interface PlainDateToStringOptions {
      calendarName?: 'auto' | 'always' | 'never' | 'critical' | undefined
    }

    interface PlainDateToZonedDateTimeOptions {
      plainTime?: PlainTimeLike | undefined
      timeZone: TimeZoneLike
    }

    interface PlainDate {
      readonly calendarId: string
      readonly era: string | undefined
      readonly eraYear: number | undefined
      readonly year: number
      readonly month: number
      readonly monthCode: string
      readonly day: number
      readonly dayOfWeek: number
      readonly dayOfYear: number
      readonly weekOfYear: number | undefined
      readonly yearOfWeek: number | undefined
      readonly daysInWeek: number
      readonly daysInMonth: number
      readonly daysInYear: number
      readonly monthsInYear: number
      readonly inLeapYear: boolean
      toPlainYearMonth(): PlainYearMonth
      toPlainMonthDay(): PlainMonthDay
      add(duration: DurationLike, options?: OverflowOptions): PlainDate
      subtract(duration: DurationLike, options?: OverflowOptions): PlainDate
      with(
        dateLike: PartialTemporalLike<DateLikeObject>,
        options?: OverflowOptions,
      ): PlainDate
      withCalendar(calendarLike: CalendarLike): PlainDate
      until(
        other: PlainDateLike,
        options?: RoundingOptionsWithLargestUnit<DateUnit>,
      ): Duration
      since(
        other: PlainDateLike,
        options?: RoundingOptionsWithLargestUnit<DateUnit>,
      ): Duration
      equals(other: PlainDateLike): boolean
      toPlainDateTime(time?: PlainTimeLike): PlainDateTime
      toZonedDateTime(timeZone: TimeZoneLike): ZonedDateTime
      toZonedDateTime(item: PlainDateToZonedDateTimeOptions): ZonedDateTime
      toString(options?: PlainDateToStringOptions): string
      toLocaleString(
        locales?: Intl.LocalesArgument,
        options?: Intl.DateTimeFormatOptions,
      ): string
      toJSON(): string
      valueOf(): never
      readonly [Symbol.toStringTag]: 'Temporal.PlainDate'
    }

    interface PlainDateConstructor {
      new (
        isoYear: number,
        isoMonth: number,
        isoDay: number,
        calendar?: string,
      ): PlainDate
      readonly prototype: PlainDate
      from(item: PlainDateLike, options?: OverflowOptions): PlainDate
      compare(one: PlainDateLike, two: PlainDateLike): number
    }
    var PlainDate: PlainDateConstructor

    interface PlainTimeToStringOptions
      extends ToStringRoundingOptionsWithFractionalSeconds<
        Exclude<TimeUnit, 'hour'>
      > {}

    interface PlainTime {
      readonly hour: number
      readonly minute: number
      readonly second: number
      readonly millisecond: number
      readonly microsecond: number
      readonly nanosecond: number
      add(duration: DurationLike): PlainTime
      subtract(duration: DurationLike): PlainTime
      with(
        timeLike: PartialTemporalLike<TimeLikeObject>,
        options?: OverflowOptions,
      ): PlainTime
      until(
        other: PlainTimeLike,
        options?: RoundingOptionsWithLargestUnit<TimeUnit>,
      ): Duration
      since(
        other: PlainTimeLike,
        options?: RoundingOptionsWithLargestUnit<TimeUnit>,
      ): Duration
      equals(other: PlainTimeLike): boolean
      round(roundTo: PluralizeUnit<TimeUnit>): PlainTime
      round(roundTo: RoundingOptions<TimeUnit>): PlainTime
      toString(options?: PlainTimeToStringOptions): string
      toLocaleString(
        locales?: Intl.LocalesArgument,
        options?: Intl.DateTimeFormatOptions,
      ): string
      toJSON(): string
      valueOf(): never
      readonly [Symbol.toStringTag]: 'Temporal.PlainTime'
    }

    interface PlainTimeConstructor {
      new (
        hour?: number,
        minute?: number,
        second?: number,
        millisecond?: number,
        microsecond?: number,
        nanosecond?: number,
      ): PlainTime
      readonly prototype: PlainTime
      from(item: PlainTimeLike, options?: OverflowOptions): PlainTime
      compare(one: PlainTimeLike, two: PlainTimeLike): number
    }
    var PlainTime: PlainTimeConstructor

    interface PlainDateTimeToStringOptions
      extends PlainDateToStringOptions,
        PlainTimeToStringOptions {}

    interface PlainDateTime {
      readonly calendarId: string
      readonly era: string | undefined
      readonly eraYear: number | undefined
      readonly year: number
      readonly month: number
      readonly monthCode: string
      readonly day: number
      readonly hour: number
      readonly minute: number
      readonly second: number
      readonly millisecond: number
      readonly microsecond: number
      readonly nanosecond: number
      readonly dayOfWeek: number
      readonly dayOfYear: number
      readonly weekOfYear: number | undefined
      readonly yearOfWeek: number | undefined
      readonly daysInWeek: number
      readonly daysInMonth: number
      readonly daysInYear: number
      readonly monthsInYear: number
      readonly inLeapYear: boolean
      with(
        dateTimeLike: PartialTemporalLike<DateTimeLikeObject>,
        options?: OverflowOptions,
      ): PlainDateTime
      withPlainTime(plainTime?: PlainTimeLike): PlainDateTime
      withCalendar(calendar: CalendarLike): PlainDateTime
      add(duration: DurationLike, options?: OverflowOptions): PlainDateTime
      subtract(duration: DurationLike, options?: OverflowOptions): PlainDateTime
      until(
        other: PlainDateTimeLike,
        options?: RoundingOptionsWithLargestUnit<DateUnit | TimeUnit>,
      ): Duration
      since(
        other: PlainDateTimeLike,
        options?: RoundingOptionsWithLargestUnit<DateUnit | TimeUnit>,
      ): Duration
      round(roundTo: PluralizeUnit<'day' | TimeUnit>): PlainDateTime
      round(roundTo: RoundingOptions<'day' | TimeUnit>): PlainDateTime
      equals(other: PlainDateTimeLike): boolean
      toString(options?: PlainDateTimeToStringOptions): string
      toLocaleString(
        locales?: Intl.LocalesArgument,
        options?: Intl.DateTimeFormatOptions,
      ): string
      toJSON(): string
      valueOf(): never
      toZonedDateTime(
        timeZone: TimeZoneLike,
        options?: DisambiguationOptions,
      ): ZonedDateTime
      toPlainDate(): PlainDate
      toPlainTime(): PlainTime
      readonly [Symbol.toStringTag]: 'Temporal.PlainDateTime'
    }

    interface PlainDateTimeConstructor {
      new (
        isoYear: number,
        isoMonth: number,
        isoDay: number,
        hour?: number,
        minute?: number,
        second?: number,
        millisecond?: number,
        microsecond?: number,
        nanosecond?: number,
        calendar?: string,
      ): PlainDateTime
      readonly prototype: PlainDateTime
      from(item: PlainDateTimeLike, options?: OverflowOptions): PlainDateTime
      compare(one: PlainDateTimeLike, two: PlainDateTimeLike): number
    }
    var PlainDateTime: PlainDateTimeConstructor

    interface ZonedDateTimeToStringOptions
      extends PlainDateTimeToStringOptions {
      offset?: 'auto' | 'never' | undefined
      timeZoneName?: 'auto' | 'never' | 'critical' | undefined
    }

    interface ZonedDateTimeFromOptions
      extends OverflowOptions,
        DisambiguationOptions {
      offset?: 'use' | 'ignore' | 'prefer' | 'reject' | undefined
    }

    interface ZonedDateTime {
      readonly calendarId: string
      readonly timeZoneId: string
      readonly era: string | undefined
      readonly eraYear: number | undefined
      readonly year: number
      readonly month: number
      readonly monthCode: string
      readonly day: number
      readonly hour: number
      readonly minute: number
      readonly second: number
      readonly millisecond: number
      readonly microsecond: number
      readonly nanosecond: number
      readonly epochMilliseconds: number
      readonly epochNanoseconds: bigint
      readonly dayOfWeek: number
      readonly dayOfYear: number
      readonly weekOfYear: number | undefined
      readonly yearOfWeek: number | undefined
      readonly hoursInDay: number
      readonly daysInWeek: number
      readonly daysInMonth: number
      readonly daysInYear: number
      readonly monthsInYear: number
      readonly inLeapYear: boolean
      readonly offsetNanoseconds: number
      readonly offset: string
      with(
        zonedDateTimeLike: PartialTemporalLike<ZonedDateTimeLikeObject>,
        options?: ZonedDateTimeFromOptions,
      ): ZonedDateTime
      withPlainTime(plainTime?: PlainTimeLike): ZonedDateTime
      withTimeZone(timeZone: TimeZoneLike): ZonedDateTime
      withCalendar(calendar: CalendarLike): ZonedDateTime
      add(duration: DurationLike, options?: OverflowOptions): ZonedDateTime
      subtract(duration: DurationLike, options?: OverflowOptions): ZonedDateTime
      until(
        other: ZonedDateTimeLike,
        options?: RoundingOptionsWithLargestUnit<DateUnit | TimeUnit>,
      ): Duration
      since(
        other: ZonedDateTimeLike,
        options?: RoundingOptionsWithLargestUnit<DateUnit | TimeUnit>,
      ): Duration
      round(roundTo: PluralizeUnit<'day' | TimeUnit>): ZonedDateTime
      round(roundTo: RoundingOptions<'day' | TimeUnit>): ZonedDateTime
      equals(other: ZonedDateTimeLike): boolean
      toString(options?: ZonedDateTimeToStringOptions): string
      toLocaleString(
        locales?: Intl.LocalesArgument,
        options?: Intl.DateTimeFormatOptions,
      ): string
      toJSON(): string
      valueOf(): never
      startOfDay(): ZonedDateTime
      getTimeZoneTransition(
        direction: 'next' | 'previous',
      ): ZonedDateTime | null
      getTimeZoneTransition(direction: TransitionOptions): ZonedDateTime | null
      toInstant(): Instant
      toPlainDate(): PlainDate
      toPlainTime(): PlainTime
      toPlainDateTime(): PlainDateTime
      readonly [Symbol.toStringTag]: 'Temporal.ZonedDateTime'
    }

    interface ZonedDateTimeConstructor {
      new (
        epochNanoseconds: bigint,
        timeZone: string,
        calendar?: string,
      ): ZonedDateTime
      readonly prototype: ZonedDateTime
      from(
        item: ZonedDateTimeLike,
        options?: ZonedDateTimeFromOptions,
      ): ZonedDateTime
      compare(one: ZonedDateTimeLike, two: ZonedDateTimeLike): number
    }
    var ZonedDateTime: ZonedDateTimeConstructor

    interface DurationRelativeToOptions {
      relativeTo?: ZonedDateTimeLike | PlainDateLike | undefined
    }

    interface DurationRoundingOptions
      extends DurationRelativeToOptions,
        RoundingOptionsWithLargestUnit<DateUnit | TimeUnit> {}

    interface DurationToStringOptions
      extends ToStringRoundingOptionsWithFractionalSeconds<
        Exclude<TimeUnit, 'hour' | 'minute'>
      > {}

    interface DurationTotalOptions extends DurationRelativeToOptions {
      unit: PluralizeUnit<DateUnit | TimeUnit>
    }

    // Use the host's Intl.DurationFormat options when the consumer includes a
    // lib that declares Intl.DurationFormat, without forcing this file to
    // reference es2025.intl for every consumer.
    type DurationFormatOptions = typeof Intl extends {
      DurationFormat: {
        new (locales?: unknown, options?: infer Options): unknown
      }
    }
      ? NonNullable<Options>
      : unknown

    interface Duration {
      readonly years: number
      readonly months: number
      readonly weeks: number
      readonly days: number
      readonly hours: number
      readonly minutes: number
      readonly seconds: number
      readonly milliseconds: number
      readonly microseconds: number
      readonly nanoseconds: number
      readonly sign: number
      readonly blank: boolean
      with(durationLike: PartialTemporalLike<DurationLikeObject>): Duration
      negated(): Duration
      abs(): Duration
      add(other: DurationLike): Duration
      subtract(other: DurationLike): Duration
      round(roundTo: PluralizeUnit<'day' | TimeUnit>): Duration
      round(roundTo: DurationRoundingOptions): Duration
      total(totalOf: PluralizeUnit<DateUnit | TimeUnit>): number
      total(totalOf: DurationTotalOptions): number
      toString(options?: DurationToStringOptions): string
      toLocaleString(
        locales?: Intl.LocalesArgument,
        options?: DurationFormatOptions,
      ): string
      toJSON(): string
      valueOf(): never
      readonly [Symbol.toStringTag]: 'Temporal.Duration'
    }

    interface DurationConstructor {
      new (
        years?: number,
        months?: number,
        weeks?: number,
        days?: number,
        hours?: number,
        minutes?: number,
        seconds?: number,
        milliseconds?: number,
        microseconds?: number,
        nanoseconds?: number,
      ): Duration
      readonly prototype: Duration
      from(item: DurationLike): Duration
      compare(
        one: DurationLike,
        two: DurationLike,
        options?: DurationRelativeToOptions,
      ): number
    }
    var Duration: DurationConstructor

    interface InstantToStringOptions extends PlainTimeToStringOptions {
      timeZone?: TimeZoneLike | undefined
    }

    interface Instant {
      readonly epochMilliseconds: number
      readonly epochNanoseconds: bigint
      add(duration: DurationLike): Instant
      subtract(duration: DurationLike): Instant
      until(
        other: InstantLike,
        options?: RoundingOptionsWithLargestUnit<TimeUnit>,
      ): Duration
      since(
        other: InstantLike,
        options?: RoundingOptionsWithLargestUnit<TimeUnit>,
      ): Duration
      round(roundTo: PluralizeUnit<TimeUnit>): Instant
      round(roundTo: RoundingOptions<TimeUnit>): Instant
      equals(other: InstantLike): boolean
      toString(options?: InstantToStringOptions): string
      toLocaleString(
        locales?: Intl.LocalesArgument,
        options?: Intl.DateTimeFormatOptions,
      ): string
      toJSON(): string
      valueOf(): never
      toZonedDateTimeISO(timeZone: TimeZoneLike): ZonedDateTime
      readonly [Symbol.toStringTag]: 'Temporal.Instant'
    }

    interface InstantConstructor {
      new (epochNanoseconds: bigint): Instant
      readonly prototype: Instant
      from(item: InstantLike): Instant
      fromEpochMilliseconds(epochMilliseconds: number): Instant
      fromEpochNanoseconds(epochNanoseconds: bigint): Instant
      compare(one: InstantLike, two: InstantLike): number
    }
    var Instant: InstantConstructor

    interface PlainYearMonthToPlainDateOptions {
      day: number
    }

    interface PlainYearMonth {
      readonly calendarId: string
      readonly era: string | undefined
      readonly eraYear: number | undefined
      readonly year: number
      readonly month: number
      readonly monthCode: string
      readonly daysInYear: number
      readonly daysInMonth: number
      readonly monthsInYear: number
      readonly inLeapYear: boolean
      with(
        yearMonthLike: PartialTemporalLike<YearMonthLikeObject>,
        options?: OverflowOptions,
      ): PlainYearMonth
      add(duration: DurationLike, options?: OverflowOptions): PlainYearMonth
      subtract(
        duration: DurationLike,
        options?: OverflowOptions,
      ): PlainYearMonth
      until(
        other: PlainYearMonthLike,
        options?: RoundingOptionsWithLargestUnit<'year' | 'month'>,
      ): Duration
      since(
        other: PlainYearMonthLike,
        options?: RoundingOptionsWithLargestUnit<'year' | 'month'>,
      ): Duration
      equals(other: PlainYearMonthLike): boolean
      toString(options?: PlainDateToStringOptions): string
      toLocaleString(
        locales?: Intl.LocalesArgument,
        options?: Intl.DateTimeFormatOptions,
      ): string
      toJSON(): string
      valueOf(): never
      toPlainDate(item: PlainYearMonthToPlainDateOptions): PlainDate
      readonly [Symbol.toStringTag]: 'Temporal.PlainYearMonth'
    }

    interface PlainYearMonthConstructor {
      new (
        isoYear: number,
        isoMonth: number,
        calendar?: string,
        referenceISODay?: number,
      ): PlainYearMonth
      readonly prototype: PlainYearMonth
      from(item: PlainYearMonthLike, options?: OverflowOptions): PlainYearMonth
      compare(one: PlainYearMonthLike, two: PlainYearMonthLike): number
    }
    var PlainYearMonth: PlainYearMonthConstructor

    interface PlainMonthDayToPlainDateOptions {
      era?: string | undefined
      eraYear?: number | undefined
      year?: number | undefined
    }

    interface PlainMonthDay {
      readonly calendarId: string
      readonly monthCode: string
      readonly day: number
      with(
        monthDayLike: PartialTemporalLike<DateLikeObject>,
        options?: OverflowOptions,
      ): PlainMonthDay
      equals(other: PlainMonthDayLike): boolean
      toString(options?: PlainDateToStringOptions): string
      toLocaleString(
        locales?: Intl.LocalesArgument,
        options?: Intl.DateTimeFormatOptions,
      ): string
      toJSON(): string
      valueOf(): never
      toPlainDate(item: PlainMonthDayToPlainDateOptions): PlainDate
      readonly [Symbol.toStringTag]: 'Temporal.PlainMonthDay'
    }

    interface PlainMonthDayConstructor {
      new (
        isoMonth: number,
        isoDay: number,
        calendar?: string,
        referenceISOYear?: number,
      ): PlainMonthDay
      readonly prototype: PlainMonthDay
      from(item: PlainMonthDayLike, options?: OverflowOptions): PlainMonthDay
    }
    var PlainMonthDay: PlainMonthDayConstructor
  }

  namespace Intl {
    type FormattableTemporalObject =
      | Temporal.PlainDate
      | Temporal.PlainYearMonth
      | Temporal.PlainMonthDay
      | Temporal.PlainTime
      | Temporal.PlainDateTime
      | Temporal.Instant

    interface DateTimeFormat {
      format(date?: FormattableTemporalObject | Date | number): string
      formatToParts(
        date?: FormattableTemporalObject | Date | number,
      ): DateTimeFormatPart[]
      formatRange(
        startDate: FormattableTemporalObject | Date | number,
        endDate: FormattableTemporalObject | Date | number,
      ): string
      formatRangeToParts(
        startDate: FormattableTemporalObject | Date | number,
        endDate: FormattableTemporalObject | Date | number,
      ): DateTimeRangeFormatPart[]
    }
  }

  interface Date {
    toTemporalInstant(): Temporal.Instant
  }
}
