export type 范_将原文本改造为包含简朴排版的新文本_排版配置 = {
    /** @default {0}     【半角数字零】。 */
    整体缩进级数: number;

    /** @default {'    '} 四个【半角空格】。 */
    整体缩进之文本: string;

    /** @default {'- '}  【半角减号】后跟一个【半角空格】。 */
    列表引领符: string;

    /** @default {'    '} 四个【半角空格】。 */
    首层缩进之文本: string;

    /** @default {'    '} 四个【半角空格】。 */
    首层缩进之文本_并含整体缩进: string;

    /** @default {'  - '} */
    首层缩进之文本_含列表引领符: string;

    /** @default {'  - '} */
    首层缩进之文本_含列表引领符_并含整体缩进: string;

    /** @default {'    '} 四个【半角空格】。本工具自身暂时不采用该值，但不妨供外界使用。 */
    非首层之单层缩进之文本: string;

    /** @default {1}     【半角数字壹】 */
    各段落间的额外空白行数: number;

    单行最大视觉宽度等效英语字母个数?: number; // TODO 暂未实现。勿用。
}

export type 范_将原文本改造为包含简朴排版的新文本_分割得到的内容结构树 = string[][];

export type 范_将原文本改造为包含简朴排版的新文本_产出 = {
    排版好的内容全文: string;
    分割好的内容结构树: 范_将原文本改造为包含简朴排版的新文本_分割得到的内容结构树;
    最终采纳的排版配置: 范_将原文本改造为包含简朴排版的新文本_排版配置;
}





/**
 * 本函数用以在纯文本环境中，对给出的文本进行简朴排版。
 * 给出的文本内容须事先插入标记，供本程序识别。
 * 标记的使用规则如下：
 *
 * 1.  【原文本】自身就包含的换行符（ “\n” 或 “\r” ）。
 *
 *     -   若单独存在（即相邻再无旁他换行符），其会被删去。
 *         文本则会在其原来的位置分割，以便另起一【行】。
 *
 *     -   若连续多个换行符彼此紧邻，它们均会被删去。
 *         文本则会在其原来的位置分割，以便另起一【段】。
 *
 *     -   若单个换行符之后有一个或多个空格跟随，
 *         则该换行符与后续空格会一并删去。
 *         文本则会在其原来的位置分割，以便另起一【段】。
 *
 *     -   特别的，“\r\n”二者连用视作【单】个换行符。
 *         但除此情形外，“\n”、“\r”二者不可混合连用。
 *         即，“\n\r”是不标准的写法，效果难以期料。本人也无意尝试。
 *
 * 2.  【原文本】中的任何标点符号，若后面 *__没有__* 空格跟随，
 *     则该标点符号之后无任何特别的排版处理。
 *
 * 3.  凡汉语的【句号】、【感叹号】、【问号】、【冒号】和【省略号】：
 *
 *     -   若后面仅 *__唯一一个__* 空格跟随，则该空格会被删去。
 *         且上述标点符号之后另起一【行】。
 *
 *     -   若后面有 *__多个__* 空格跟随，则这些空格会被删去。
 *         且上述标点符号之后另起一【段】。
 *
 * 4.  凡汉语的【顿号】、【逗号】和【分号】：
 *
 *     -   若后面有 *__一个或多个__* 空格跟随，则这些空格会被删去。
 *         且上述标点符号之后另起一【行】。
 *         不妨强调，这些标点之后 *__永无可能__* 另起一【段】
 *
 * 5.  汉语【 _后_ 引号】较为特殊：
 *
 *     -   若后面 *__没有__* 空格跟随，照例不做任何处理。
 *
 *     -   若后面仅 *__唯一一个__* 空格跟随，仍不做任何处理！
 *         这是因为，不少时候为了视觉美观我（们）希望故意
 *         在【前引号】之前、【后引号】之后各留一个空格。
 *         此时，我（们）的意图 _并不是_ 暗示本工具在此【后引号】之后另起一行。
 *
 *     -   若后面 *__恰好有 2 个__* 空格跟随，则这两个空格会被删去。
 *         且该【后引号】之后会另起一【行】。
 *
 *     -   若后面有 *__3 个或更多__* 空格跟随，则这些空格全会被删去。
 *         且该【后引号】之后会另起一【段】。
 */
export function 将原文本改造为包含简朴排版的新文本 ({
    原文本,
    列表引领符,
    单层缩进空格数或单层缩进之文本,
    整体缩进级数,
    各段落间的额外空白行数,
}: {
    原文本?: string;

    /** @default {'- '}  【半角减号】后跟一个【半角空格】。 */
    列表引领符?: string;

    /** @default {'    '} 四个【半角空格】。 */
    单层缩进空格数或单层缩进之文本?: number | string;

    /** @default {0}     【半角数字零】。 */
    整体缩进级数?: number;

    /** @default {1}     【半角数字壹】 */
    各段落间的额外空白行数?: number;
} = {}): 范_将原文本改造为包含简朴排版的新文本_产出 {
    let 单层缩进之文本: string = ' '.repeat(4)

    if (typeof 单层缩进空格数或单层缩进之文本 === 'string') {
        if (单层缩进空格数或单层缩进之文本.trim()) {
            单层缩进之文本 = 单层缩进空格数或单层缩进之文本
        } else {
            const 等效的数字 = +单层缩进空格数或单层缩进之文本
            if (0 < 等效的数字 && 等效的数字 < 128) {
                单层缩进之文本 = ' '.repeat(等效的数字)
            } else {
                单层缩进之文本 = 单层缩进空格数或单层缩进之文本
            }
        }
    } else if (typeof 单层缩进空格数或单层缩进之文本 === 'number') {
        if (0 < 单层缩进空格数或单层缩进之文本 && 单层缩进空格数或单层缩进之文本 < 128) {
            单层缩进之文本 = ' '.repeat(单层缩进空格数或单层缩进之文本)
        }
    }

    if (typeof 列表引领符 !== 'string') {
        列表引领符 = '- '
    }

    整体缩进级数 = +(整体缩进级数 || 0)
    if (!(整体缩进级数 > 0)) {
        整体缩进级数 = 0
    }

    各段落间的额外空白行数 = +(各段落间的额外空白行数 || -1)
    if (!(各段落间的额外空白行数 >= 0)) {
        各段落间的额外空白行数 = 1
    }

    const 整体缩进之文本 = 单层缩进之文本.repeat(整体缩进级数)

    let 首层缩进之文本 = ''
    let 首层缩进之文本_含列表引领符 = ''
    if (列表引领符.length > 0) {
        首层缩进之文本 = 单层缩进之文本.repeat(Math.ceil((列表引领符.length + 1) / 单层缩进之文本.length))
        首层缩进之文本_含列表引领符 = `${首层缩进之文本.slice(0, -列表引领符.length)}${列表引领符}`
    }

    const 非首层之单层缩进之文本 = 单层缩进之文本 // 在本函数内部无用，但可供外界采用。

    const 首层缩进之文本_并含整体缩进          = `${整体缩进之文本}${首层缩进之文本}`
    const 首层缩进之文本_含列表引领符_并含整体缩进 = `${整体缩进之文本}${首层缩进之文本_含列表引领符}`





    let 各段落文本之列表: any[] = [ 原文本 ]

    ;[
        { 分割符或分割正则表达式: /。 {2,}/, 在分割符处须补回的内容: '。' },
        { 分割符或分割正则表达式: /！ {2,}/, 在分割符处须补回的内容: '！' },
        { 分割符或分割正则表达式: /？ {2,}/, 在分割符处须补回的内容: '？' },
        { 分割符或分割正则表达式: /” {3,}/, 在分割符处须补回的内容: '”' },
        { 分割符或分割正则表达式: /： {2,}/, 在分割符处须补回的内容: '：' },
        { 分割符或分割正则表达式: /…… {2,}/, 在分割符处须补回的内容: '……' },

        { 分割符或分割正则表达式: /\n{2,}|\n +/,       在分割符处须补回的内容: '' },
        { 分割符或分割正则表达式: /\r{2,}|\r +/,       在分割符处须补回的内容: '' },
        { 分割符或分割正则表达式: /(\r\n){2,}|\r\n +/, 在分割符处须补回的内容: '' },
    ].forEach(分割方案 => {
        各段落文本之列表 = 对文本列表逐项分割并将结果列表展平({
            原文本或原文本列表: 各段落文本之列表,
            ...分割方案,
        })
    })





    const 各段落文本列表之列表: string[][] = 各段落文本之列表.map(某段落之文本 => {
        let 某段落中各行文本之列表 = [ 某段落之文本 ]

        ;[
            { 分割符或分割正则表达式: /。 /, 在分割符处须补回的内容: '。' },
            { 分割符或分割正则表达式: /！ /, 在分割符处须补回的内容: '！' },
            { 分割符或分割正则表达式: /？ /, 在分割符处须补回的内容: '？' },
            { 分割符或分割正则表达式: /” {2}/, 在分割符处须补回的内容: '”' },
            { 分割符或分割正则表达式: /： /, 在分割符处须补回的内容: '：' },
            { 分割符或分割正则表达式: /…… /, 在分割符处须补回的内容: '……' },

            { 分割符或分割正则表达式: /、 +/, 在分割符处须补回的内容: '、' },
            { 分割符或分割正则表达式: /， +/, 在分割符处须补回的内容: '，' },
            { 分割符或分割正则表达式: /； +/, 在分割符处须补回的内容: '；' },

            { 分割符或分割正则表达式: /\n/,   在分割符处须补回的内容: '' },
            { 分割符或分割正则表达式: /\r/,   在分割符处须补回的内容: '' },
            { 分割符或分割正则表达式: /\r\n/, 在分割符处须补回的内容: '' },
        ].forEach(分割方案 => {
            某段落中各行文本之列表 = 对文本列表逐项分割并将结果列表展平({
                原文本或原文本列表: 某段落中各行文本之列表,
                ...分割方案,
            })
        })

        return 某段落中各行文本之列表
    })





    const 排版好的内容全文 = 各段落文本列表之列表.map((某段落中各行文本之列表) => {
        return 某段落中各行文本之列表.map((某行之文本, 行之内部编号) => {
            const 行号 = 行之内部编号 + 1
            const 行前缀内容 = `${整体缩进之文本}${行号 === 1 ? 首层缩进之文本_含列表引领符 : 首层缩进之文本}`
            return `${行前缀内容}${某行之文本}`
        }).join('\n')
    }).join('\n'.repeat(1 + 各段落间的额外空白行数))





    const 产出: 范_将原文本改造为包含简朴排版的新文本_产出 = {
        排版好的内容全文,

        分割好的内容结构树: 各段落文本列表之列表,

        最终采纳的排版配置: {
            整体缩进级数,
            整体缩进之文本,
            列表引领符,
            首层缩进之文本,
            首层缩进之文本_并含整体缩进,
            首层缩进之文本_含列表引领符,
            首层缩进之文本_含列表引领符_并含整体缩进,
            非首层之单层缩进之文本,
            各段落间的额外空白行数,
        },
    }

    return 产出
}





export type 范_对文本列表逐项分割并将结果列表展平 = {
    (配置项集: {
        原文本或原文本列表: string[];
        分割符或分割正则表达式?: string | RegExp;
        在分割符处须补回的内容?: string;
    }): string[];

    (配置项集: {
        原文本或原文本列表: string;
        分割符或分割正则表达式?: string | RegExp;
        在分割符处须补回的内容?: string;
    }): string;

    (配置项集?: {
        原文本或原文本列表?: any;
        分割符或分割正则表达式?: string | RegExp;
        在分割符处须补回的内容?: string;
    }): any;
}

/**
 * 本函数接受原文信息，并据此有所产出。原文可以是文本列表（“`string[]`”），也可以是单一文本（“`string`”）。
 *
 * -   如果原文是文本列表（“`string[]`”），本程序会
 *
 *     1.  将其中的所有文本逐一分割，
 *         故从每一个原始文本各得到一个文本片段列表（“`string[]`”）。
 *
 *     2.  将这些文本片段列表汇总在一个列表中，
 *         临时得到一个双层嵌套列表，即 （“`string[][]`”）。
 *
 * -   如果给出的原文是一个文本“`string`”）而非文本列表（“`string[]`”），
 *     则本函数会先创建一个列表，将该文本包裹其中，而后照常处理该列表。
 *
 | - - - - - - - - - - - - - - - - - - - - -
 *
 * 本函数接受唯一的参数，不妨称 `配置项集` 。配置项集中可以给出以下 3 个属性。
 *
 | - - - - - - - - - - - - - - - - - - - - -
 *
 * 1. `配置项集.原文本或原文本列表`：
 *
 *     顾名思义，该值可为文本或文本列表。若为文本，则本函数会先创建一个列表，将该文本包裹其中，而后照常处理该列表。
 *
 * 2. `配置项集.分割符或分割正则表达式`：
 *
 *     顾名思义，可为文本，亦可为正则表达式实例。用以分隔原文本列表中的每一项文本。
 *
 * 3. `配置项集.在分割符处须补回的内容`：
 *
 *     我们知道， JavaScript 和 TypeScript 中的字符串分割函数（“`split`”）
 *     无法在分割得到的结果列表中包含分割符本身。即，分割符会消失在结果中。
 *     为确保原文本在经历排版设计后内容仍完整无缺，
 *     需在分割后将那些用作分割符的字符补回。
 *     此项即为须补回的字符。
 *
 *     顺便指出，该字符可以任意设计，故实际上可以实现对用作分割符的文本进行“偷换”。
 *
 *     还需注意，
 *
 *     -   如果 `配置项集.分割符或分割正则表达式` 是文本，
 *         则 `配置项集.在分割符处须补回的内容` 可以省略。
 *         若省略，则其取值会照搬前者（即 `配置项集.分割符或分割正则表达式` ）。
 *         丢失什么就补回什么，这也合乎常情。
 *
 *     -   如果 `配置项集.分割符或分割正则表达式` 是正则表达式，
 *         则 `配置项集.在分割符处须补回的内容` 虽然可以省略，但本程序会给出警告。
 *         因为，从正则表达式的 “`.toString`” 得到的文本视作“补回的”文本往往是不合适的！
 *
 *     -   另需指出，补回的文本配置为“空字符串”是允许的，不会视为省略。
 */
export const 对文本列表逐项分割并将结果列表展平: 范_对文本列表逐项分割并将结果列表展平 = 配置项集 => {
    if (!配置项集 || typeof 配置项集 !== 'object') { 配置项集 = {} }

    const {
        原文本或原文本列表: 原文本或原文本列表_给出值,
        分割符或分割正则表达式: 分割符或分割正则表达式_给出值,
        在分割符处须补回的内容: 在分割符处须补回的内容_给出值,
    } = 配置项集



    let 原文本列表_采纳值1: any[]

    if (typeof 原文本或原文本列表_给出值 === 'string') {
        原文本列表_采纳值1 = [ 原文本或原文本列表_给出值 ]
    } else if (Array.isArray(原文本或原文本列表_给出值)) {
        原文本列表_采纳值1 = 原文本或原文本列表_给出值
    } else {
        原文本列表_采纳值1 = []
    }

    const 原文本列表_采纳值2: string[] = 原文本列表_采纳值1.filter(
        某项内容 => typeof 某项内容 === 'string' && !!某项内容
    )

    if (原文本列表_采纳值2.length < 1) {
        // console.debug('给出的原文内容无效，或内容全空。')
        return 原文本或原文本列表_给出值
    }



    const 在分割符处须补回内容未给出 = typeof 在分割符处须补回的内容_给出值 !== 'string'

    let 分割符或分割正则表达式_采纳值: string | RegExp
    let 分割符等效的文本 = ''

    let 在分割符处须补回的内容_采纳值: string
    let 分割符为正则表达式时补回内容却未给出 = false

    if (typeof 分割符或分割正则表达式_给出值 === 'string') {
        分割符或分割正则表达式_采纳值 = 分割符或分割正则表达式_给出值
        分割符等效的文本 = 分割符或分割正则表达式_给出值
    } else {
        if (分割符或分割正则表达式_给出值 instanceof RegExp) {
            分割符或分割正则表达式_采纳值 = 分割符或分割正则表达式_给出值
            分割符等效的文本 = 分割符或分割正则表达式_给出值.toString()

            分割符为正则表达式时补回内容却未给出 = 在分割符处须补回内容未给出
        } else {
            分割符或分割正则表达式_采纳值 = ''
        }
    }

    if (!在分割符处须补回内容未给出) {
        在分割符处须补回的内容_采纳值 = 在分割符处须补回的内容_给出值
    } else {
        在分割符处须补回的内容_采纳值 = 分割符等效的文本

        if (分割符为正则表达式时补回内容却未给出) {
            console.warn(`给出的【分割符】系正则表达式，但【分割符处须补回的内容】并未明确给出。故补回的内容是不可靠的！据目前给出的配置，拟在各分割处补回该内容： "${在分割符处须补回的内容_采纳值}"。`)
        }
    }

    if (!分割符或分割正则表达式_采纳值) {
        console.debug('【分割符】为空字符串。')
    }



    const 两级嵌套之列表 = 原文本列表_采纳值2.map(原文某项文本 => {
        return 原文某项文本.split(分割符或分割正则表达式_采纳值).map((分割后的某文本片段, 片段之内部编号, 分割得到的片段列表) => {
            const 不是最末的片段 = 片段之内部编号 < 分割得到的片段列表.length - 1
            return 不是最末的片段 ? `${分割后的某文本片段}${在分割符处须补回的内容_采纳值}` : 分割后的某文本片段
        })
    })

    const 展平后的单级列表 = 两级嵌套之列表.reduce((展平后的文本片段列表, 某原文本分割而得的片段列表) => {
        return [
            ...展平后的文本片段列表,
            ...某原文本分割而得的片段列表,
        ]
    }, [])

    return 展平后的单级列表
}
