import type { IsAny } from '../any/any_type.js'

/**
 * Check if the type `T` is exactly `unknown`.
 *
 * ```ts
 * type R = UnknownType<unknown> // unknown
 *
 * type R = UnknownType<number> // never
 * type R = UnknownType<never> // never
 * ```
 */
export type UnknownType<T, Then = T, Else = never> = IsAny<
	T,
	Else,
	[T, unknown] extends [unknown, T] ? Then : Else
>

/**
 * Is the type `T` exactly `unknown`.
 *
 * ```ts
 * type R = IsUnknown<unknown> // true
 *
 * type R = IsUnknown<number> // false
 * type R = IsUnknown<never> // false
 * ```
 */
export type IsUnknown<T, Then = true, Else = false> = UnknownType<T, Then, Else>

/**
 * Check if the type `T` is not `unknown`.
 *
 * ```ts
 * type R = NotUnknownType<unknown> // never
 *
 * type R = NotUnknownType<never> // never
 * type R = NotUnknownType<number> // number
 * type R = NotUnknownType<string | boolean> // string | boolean
 * ```
 */
export type NotUnknownType<T, Then = T, Else = never> = UnknownType<T, Else, Then>

/**
 * Is the type `T` not exactly `unknown`.
 *
 * ```ts
 * type R = IsNotUnknown<unknown> // false
 *
 * type R = IsNotUnknown<never> // true
 * type R = IsNotUnknown<number> // true
 * type R = IsNotUnknown<string | boolean> // true
 * ```
 */
export type IsNotUnknown<T, Then = true, Else = false> = UnknownType<T, Else, Then>

/**
 * 🌪️ *filter*
 *
 * Returns `T` if `T` is not `unknown`, otherwise `Else`.
 *
 * @example
 * ```ts
 * type R = NotUnknownOr<number, string> // number
 * type R = NotUnknownOr<unknown, number> // number
 * ```
 */
export type NotUnknownOr<T, Else> = UnknownType<T, Else, T>
