import { backTicks, heading } from '../../../libs/markdown/index.js';
import { escapeChars } from '../../../libs/utils/index.js';
import { ReflectionKind, ReflectionType, UnionType, } from 'typedoc';
export function parametersList(model, options) {
    const firstOptionalParamIndex = model.findIndex((parameter) => parameter.flags.isOptional);
    const md = [];
    model.forEach((parameter, i) => {
        const row = [];
        const isOptional = parameter.flags.isOptional ||
            (firstOptionalParamIndex !== -1 && i > firstOptionalParamIndex);
        const optional = isOptional ? '?' : '';
        const name = `${escapeChars(parameter.name)}${optional}`;
        row.push(heading(options.headingLevel + 1, name));
        if (parameter.type instanceof UnionType && parameter.type?.types) {
            const unions = [];
            if (parameter.comment) {
                row.push(this.partials.comment(parameter.comment));
            }
            parameter.type?.types.forEach((type) => {
                const hasUsefulTypeDetails = this.helpers.hasUsefulTypeDetails(type);
                if (type instanceof ReflectionType) {
                    const typeOut = this.partials.someType(type, {
                        forceCollapse: true,
                    });
                    if (hasUsefulTypeDetails) {
                        const usefulDetails = [];
                        usefulDetails.push('\n\n');
                        usefulDetails.push(typeOut);
                        usefulDetails.push(getReflectionType(this, options, parameter, type));
                        usefulDetails.push('\n\n');
                        unions.push(usefulDetails.join('\n\n'));
                    }
                    else {
                        unions.push(typeOut);
                    }
                }
                else {
                    unions.push(this.partials.someType(type, { forceCollapse: true }));
                }
            });
            row.push(unions
                .join(' | ')
                .split('\n')
                .map((ln) => ln.trim())
                .join('\n'));
        }
        else {
            if (parameter.type instanceof ReflectionType) {
                if (parameter.type.declaration?.signatures) {
                    row.push(this.partials.someType(parameter.type, { forceCollapse: true }));
                }
                row.push(`${'\n\n'}${getReflectionType(this, options, parameter, parameter.type)}`);
            }
            else {
                row.push(getOtherType(this, parameter));
            }
        }
        md.push(row.join('\n\n'));
    });
    return md.join('\n\n');
}
function getOtherType(context, parameter, skipHeading = false) {
    const rest = parameter.flags.isRest ? '...' : '';
    const identifier = [];
    const md = [];
    if (!skipHeading) {
        identifier.push(context.partials.someType(parameter.type, { forceCollapse: true }));
    }
    if (parameter.defaultValue) {
        identifier.push(' = ' + backTicks(context.helpers.getParameterDefaultValue(parameter)));
    }
    md.push(`${rest}${identifier.join('')}`);
    if (parameter.comment) {
        md.push(context.partials.comment(parameter.comment));
    }
    return md.join('\n\n');
}
function getReflectionType(context, options, parameter, type) {
    const flatten = flattenParams({
        name: parameter.name,
        type,
    }, true);
    const block = [];
    const typeMd = [];
    if (parameter.comment) {
        block.push(context.partials.comment(parameter.comment));
    }
    flatten?.forEach((flat) => {
        const name = [flat.name];
        if (flat.flags.isOptional) {
            name.push('?');
        }
        typeMd.push('\n' + heading(options.headingLevel + 2, name.join('')));
        typeMd.push(getOtherType(context, flat));
    });
    block.push(typeMd.join('\n\n'));
    return block.join('\n\n');
}
function flattenParams(current, skip = false) {
    return current.type?.declaration?.children?.reduce((acc, child) => {
        const childObj = {
            ...child,
            name: skip ? child.name : `${current.name}.${child.name}`,
        };
        return parseParams(childObj, acc);
    }, []);
}
function parseParams(current, acc) {
    const shouldFlatten = current.type?.declaration?.kind === ReflectionKind.TypeLiteral &&
        current.type?.declaration?.children;
    return shouldFlatten
        ? [...acc, current, ...flattenParams(current)]
        : [...acc, current];
}
