/**
 * @license Copyright (c) 2017-2025, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md.
 */

// This file contains several types and definitions used in the Typedoc converter mechanism.
// It is not loaded anywhere in Umberto, and should not cause any errors.

import type * as ReflectionKind from './reflectionkind.js';

export type TypedocCommentItem = {
	kind: 'text' | 'code' | 'inline-tag';
	text: string;

	/**
	 * Available when `kind === 'inline-tag'`.
	 */
	tag?: string;

	/**
	 * Available if `tag === '@link'` and it points to an existing reflection.
	 */
	target?: number;
};

export type BaseReflection<T> = {
	id: number;
	kind: T;
	name: string;
	variant: 'declaration' | 'reference' | 'signature';
	flags: Record<
		'isReadonly' | 'isPrivate' | 'isProtected' | 'isPublic' | 'isStatic' | 'isOptional' | 'isRest' | 'isExternal',
		true | undefined
	>;
	comment?: {
		summary: Array<TypedocCommentItem>;
		blockTags: Array<{
			tag: `@${ string }`;
			name: string;
			content: Array<TypedocCommentItem>;
		}>;
		modifierTags: Array<`@${ string }`>;
	};
	sources?: Array<{
		fileName: string;
		line: number;
		character: number;
		url: string;
	}>;
};

export type ProjectReflection = BaseReflection<typeof ReflectionKind.Project> & {
	children: Array<ModuleReflection>;
};

export type ModuleReflection = BaseReflection<typeof ReflectionKind.Module> & {
	children: Array<
		VariableReflection |
		FunctionReflection |
		CKEditor5ErrorReflection |
		ClassReflection |
		InterfaceReflection |
		ReferenceReflection |
		LiteralObjectReflection
	>;
};

export type VariableReflection = BaseReflection<typeof ReflectionKind.Variable> & {
	type: AvailableTypes;
	defaultValue: string;
};

export type ReferenceReflection = BaseReflection<typeof ReflectionKind.Reference> & {
	variant: 'reference';
	target: number;
};

export type LiteralObjectReflection = BaseReflection<typeof ReflectionKind.TypeLiteral> & {
	type?: LiteralTypeReflection;
};

/**
 * CKEditor 5 structures.
 */

export type CKEditor5ErrorReflection = BaseReflection<typeof ReflectionKind.Document> & {
	isCKEditor5Error: true;
	parameters: Array<ParameterReflection>;
};

export type CKEditor5EventReflection = BaseReflection<typeof ReflectionKind.Document> & {
	parameters: Array<ParameterReflection>;
};

export type Eventable = {
	ckeditor5Events: Array<CKEditor5EventReflection>;
};

/**
 * OOP.
 */

export type TypeParameterReflection = BaseReflection<typeof ReflectionKind.TypeParameter> & {
	type?: AvailableTypes;
	default?: LiteralOrIntrinsic | ReferenceType;
};

export type Inheritable = {
	extendedTypes: Array<ReferenceType>;
	implementedTypes: Array<ReferenceType>;
	typeParameters: Array<TypeParameterReflection>;
	inheritedFrom: ReferenceType;
};

export type ClassReflection = BaseReflection<typeof ReflectionKind.Class> & Inheritable & Eventable & {
	children: Array<AccessorReflection | ConstructorReflection | MethodReflection | PropertyReflection>;
};

export type InterfaceReflection = BaseReflection<typeof ReflectionKind.Interface> & Inheritable & Eventable & {
	children: Array<AccessorReflection | MethodReflection | PropertyReflection>;
};

export type AccessorReflection = BaseReflection<typeof ReflectionKind.Accessor> & {
	getSignature: Omit<
		CallSignatureReflection<typeof ReflectionKind.GetSignature>,
		'typeParameters' | 'parameters'
	>;
	setSignature: Omit<
		CallSignatureReflection<typeof ReflectionKind.SetSignature>,
		'typeParameters'
	>;
};

export type PropertyReflection = BaseReflection<typeof ReflectionKind.Property> & {
	type: AvailableTypes;
};

export type ComputedPropertyReflection = BaseReflection<typeof ReflectionKind.IndexSignature>;

/**
 * Callables.
 */

export type TypedocCallable<T> = {
	signatures: Array<CallSignatureReflection<T>>;
};

export type ParameterReflection = BaseReflection<typeof ReflectionKind.Parameter> & {
	type: AvailableTypes;
};

export type CallSignatureReflection<T> = BaseReflection<T> & {
	type: AvailableTypes;
	parameters?: Array<ParameterReflection>;
	typeParameters?: Array<TypeParameterReflection>;
	inheritedFrom?: ReferenceType;
	children?: Array<PropertyReflection>;
	indexSignatures?: Array<IndexSignatureType>;
};

export type ConstructorReflection =
	BaseReflection<typeof ReflectionKind.Constructor> & TypedocCallable<typeof ReflectionKind.ConstructorSignature>;

export type MethodReflection =
	BaseReflection<typeof ReflectionKind.Method> & TypedocCallable<typeof ReflectionKind.CallSignature>;

export type FunctionReflection =
	BaseReflection<typeof ReflectionKind.Function> & TypedocCallable<typeof ReflectionKind.CallSignature>;

/**
 * Types.
 */

export type AvailableTypes = string |
	LiteralOrIntrinsic |
	ReferenceType |
	TypeOperator |
	LiteralTypeReflection |
	UnionType |
	ArrayType |
	IndexAccessType |
	TupleType |
	NamedTupleMemberType |
	IntersectionType |
	QueryType |
	MappedType |
	ConditionalType |
	TemplateLiteralType |
	PredicateType;

export type LiteralTypeReflection = BaseReflection<typeof ReflectionKind.TypeLiteral> & {
	type: 'reflection';
	declaration?: {
		name: '__type';
		children?: Array<PropertyReflection>;
		signatures?: TypedocCallable<typeof ReflectionKind.CallSignature>;
		indexSignatures?: Array<IndexSignatureType>;
	};
};

export type IndexSignatureType = BaseReflection<typeof ReflectionKind.IndexSignature> & {
	name: '__index';
	variant: 'signature';
	parameters: Array<ParameterReflection>;
	type: AvailableTypes;
};

export type UnionType = {
	type: 'union';
	types: Array<LiteralTypeReflection>;
};

export type ArrayType = {
	type: 'array';
	elementType: AvailableTypes;
};

export type IndexAccessType = {
	type: 'indexedAccess';
	objectType: AvailableTypes;
	indexType: AvailableTypes;
};

export type TupleType = {
	type: 'tuple';
	elements: Array<AvailableTypes>;
};

export type NamedTupleMemberType = {
	type: 'namedTupleMember';
	element: AvailableTypes;
};

export type IntersectionType = {
	type: 'intersection';
	types: Array<LiteralTypeReflection>;
};

export type QueryType = {
	type: 'query';
	queryType: {
		name: string;
	};
};

export type MappedType = {
	type: 'mapped';
	parameter: string;
	parameterType?: TypeOperator | string;
	templateType: LiteralOrIntrinsic;
	optionalModifier?: string;
};

export type ConditionalType = {
	type: 'conditional';
	checkType: ReferenceType;
	extendsType: AvailableTypes;
	trueType: AvailableTypes;
	falseType: AvailableTypes;
};

export type TemplateLiteralType = {
	type: 'templateLiteral';
	tail: Array<{
		type: AvailableTypes;
		suffix: string;
	}>;
	head: string;
};

export type PredicateType = {
	type: 'predicate';
	targetType: AvailableTypes;
};

export type ReferenceType = {
	type: 'reference';
	target: number | {
		packageName: 'typescript';
		packagePath: string;
		qualifiedName: string;
	};
	typeArguments?: Array<TypeParameterReflection>;
};

export type TypeOperator = {
	type: 'typeOperator';
	operator: string;
	target: ReferenceType;
};

type LiteralOrIntrinsic =
	{
		type: 'literal';
		value: string | number | boolean | null;
	} |
	{
		type: 'intrinsic';
		name: string;
	};
