import { decode } from "js-base64"
import { PrinterParam, TableColumn, ColumnInfo, SettingValues, OptionValues, IFPTableValue, DetailOptionValues } from "../../renderers/Lion/LabelPrint/types"
import {
    FormTemplate, LabelNumber, LabelTemplate, LabelPageParam, LabelCodeType, LabelPrintStyleParam,
    LabelText, LabelBarCode, LabelEllipse, LabelHtml, LabelLine, LabelRect, LabelShape, LabelTable, LabelImage, Rect, DetailTemplate, CodeRect, TitleRect
} from "./type"
import moment from 'moment'
import { calcFn, sortFn } from "../utils"
import { getCellValue } from "../../store/utils/commonTableFunction"
import { flatMap } from "lodash"

type ColumnDataType = IFPTableValue

type TemplateSetting = Pick<SettingValues, 'width' | 'height' | 'direction' | 'left' | 'right' | 'bottom' | 'top'>

export const buildDetailTemplate = (settings: TemplateSetting, options: DetailOptionValues & { subTitle?: string, extraTitle: string, codeValue?: string, codeLabel?: string }): DetailTemplate => {
    const userInfo = sessionStorage.getItem('userInfo') ?? '{}'
    const userObj = userInfo && JSON.parse(userInfo)
    const { width, height, direction, top: defaultTop, bottom: defaultBottom, left: defaultLeft, right: defaultRight } = settings
    const { showLogo, title, showTitle, showDynamicSubTitles, dynamicSubTiltes, showPrinter, showDate, subTitle, extraTitle, showPageNum, showBarCode, showQRCode, codeLabel, codeValue } = options
    const pageWidth = direction == 'vertical' ? width : height
    const pageHeight = direction == 'vertical' ? height : width

    const headerHeight = 15
    const codeWidth = (showBarCode || showQRCode) ? showBarCode ? 60 : 25 : 0
    const codeHeight = (showBarCode || showQRCode) ? showBarCode ? 15 : 25 : 0
    const titleHeight = showTitle ? 5 : 0
    const titleMarginTop = 3
    const subTitleHeight = showDynamicSubTitles ? 6 : 0
    const subTitleMarginTop = showDynamicSubTitles ? 3 : 0
    const subTitleCount = dynamicSubTiltes.length
    const htmlMarginTop = 3
    const htmlMarginBottom = 8

    const footerHeight = 4
    const pageNumWidth = 12

    const rect: Rect = { top: defaultTop, left: defaultLeft, width: pageWidth - defaultLeft - defaultRight, height: pageHeight - defaultTop - defaultBottom }
    const headerRect: Rect = { top: rect.top, left: rect.left, width: rect.width, height: headerHeight }
    const logoRect: Rect = { top: headerRect.top, left: headerRect.left, width: showLogo ? headerRect.height : 0, height: showLogo ? headerRect.height : 0, content: showLogo ? `<img src="./public/images/sanfu.png"/>` : '' }
    const codeRect: CodeRect = { top: headerRect.top, left: headerRect.width + headerRect.left - codeWidth, width: codeWidth, height: codeHeight, label: '', codeType: showQRCode ? 'QRCode' : 'code39', content: (showBarCode || showQRCode) ? codeValue : undefined }
    const codeLabelRect: Rect = { top: codeRect.top + codeRect.height + 1, left: codeRect.left, width: codeRect.width + 5, height: 10, content: `${codeLabel}:${codeValue}` }

    const extraTitleRect: Rect = { top: headerRect.top, left: headerRect.left + logoRect.width, width: headerRect.width - logoRect.width, height: headerRect.height, content: extraTitle }
    const titleRect: Rect = { top: headerRect.top + headerRect.height + titleMarginTop, left: rect.left, width: rect.width, height: titleHeight, content: showTitle ? title + (subTitle ? `[${subTitle}]` : '') : '' }

    const subTitleRect: Rect = { top: titleRect.top + titleRect.height + subTitleMarginTop, left: defaultLeft, width: rect.width, height: subTitleHeight }
    const subTitleRect1: Rect = { top: subTitleRect.top, left: subTitleRect.left, width: subTitleRect.width / (subTitleCount || 1), height: subTitleRect.height, content: showDynamicSubTitles ? dynamicSubTiltes[0] : undefined }
    const subTitleRect2: Rect = { top: subTitleRect.top, left: subTitleCount <= 1 ? 0 : subTitleRect.left + (subTitleRect.width / subTitleCount), width: subTitleCount <= 1 ? 0 : subTitleRect.width / (subTitleCount || 1), height: subTitleRect.height, content: showDynamicSubTitles ? dynamicSubTiltes[1] : undefined }
    const subTitleRect3: Rect = { top: subTitleRect.top, left: subTitleCount <= 2 ? 0 : subTitleRect.left + (subTitleRect.width / subTitleCount * (subTitleCount - 1)), width: subTitleCount <= 2 ? 0 : subTitleRect.width / (subTitleCount || 1), height: subTitleRect.height, content: showDynamicSubTitles ? dynamicSubTiltes[2] : undefined }

    const footerRect: Rect = { top: rect.height + defaultTop - footerHeight, left: rect.left, width: rect.width, height: footerHeight }
    const printerRect: Rect = { top: footerRect.top, left: rect.left, width: footerRect.width * 0.3, height: showPrinter ? footerRect.height : 0, content: showPrinter ? `打印者:${userObj.user_name ?? ''}` : '' }
    const dateRect: Rect = { top: footerRect.top, left: footerRect.left + printerRect.width, width: footerRect.width * 0.4, height: showDate ? footerRect.height : 0, content: showDate ? `打印时间:${moment(new Date()).format('YYYY-MM-DD HH:mm:ss')}` : '' }
    const numRect: Rect = { top: footerRect.top, left: footerRect.left + printerRect.width + dateRect.width + (footerRect.width * 0.3 - pageNumWidth * 2) - 2, width: pageNumWidth, height: footerRect.height, content: showPageNum ? '第#页' : '' }
    const sumRect: Rect = { top: footerRect.top, left: numRect.left + numRect.width + 2, width: pageNumWidth, height: footerRect.height, content: showPageNum ? '共#页' : '' }

    const htmlRect: Rect = {
        top: subTitleRect.top + subTitleRect.height + htmlMarginTop,
        left: rect.left,
        width: rect.width,
        height: footerRect.top - (subTitleRect.top + subTitleRect.height + htmlMarginTop) - htmlMarginBottom
    }

    return {
        header: headerRect, logo: logoRect, code: codeRect, codeLabel: codeLabelRect, extraTitle: extraTitleRect, title: titleRect,
        subTitle: subTitleRect, subTitle1: subTitleRect1, subTitle2: subTitleRect2, subTitle3: subTitleRect3,
        html: htmlRect, date: dateRect, printer: printerRect, footer: footerRect, num: numRect, sum: sumRect
    }
}

export const buildFormTemplate = (settings: TemplateSetting, options: OptionValues): FormTemplate => {
    const userInfo = sessionStorage.getItem('userInfo') ?? '{}'
    const userObj = userInfo && JSON.parse(userInfo)

    const { width, height, direction, top: defaultTop, bottom: defaultBottom, left: defaultLeft, right: defaultRight } = settings
    const { showHeaderTitle, headerTitle, showHeaderLine, showLogo, showTitle, titleAllPrint, title, showSubTitle, subTitleAllPrint, subTitle = [], showFooterLine, showFooterTitle, footerTitle, showPrinter, showDate, showPageNum } = options

    const pageWidth = direction == 'vertical' ? width : height
    const pageHeight = direction == 'vertical' ? height : width

    const headerHeight = (showLogo || showHeaderTitle || showHeaderLine) ? 18 : 0
    const footerHeight = 5
    const titleHeight = 3.4
    const subTitleHeight = showSubTitle ? 6 : 0
    const subTitleMarginTop = showSubTitle ? 3 : 0
    const subTitleCount = subTitle.length
    const pageNumWidth = 12
    const lineHeight = 0.3

    const headerRect: Rect = { top: defaultTop, left: defaultLeft, width: pageWidth - defaultLeft - defaultRight, height: headerHeight }
    const headerLineRect = { top: headerRect.top + headerRect.height + 2, left: headerRect.left, width: headerRect.width, height: showHeaderLine ? lineHeight : 0 }
    const logoRect: Rect = { top: headerRect.top, left: headerRect.left, width: showLogo ? headerRect.height : 0, height: showLogo ? headerRect.height : 0, content: showLogo ? `<img src="./public/images/sanfu.png"/>` : '' }
    const headerTitleRect: Rect = { top: headerRect.top + (headerRect.height / 2 - 2), left: headerRect.left + logoRect.width + 5, width: headerRect.width - logoRect.width - 5, height: titleHeight, content: showHeaderTitle ? headerTitle : '' }

    const footerRect: Rect = { top: pageHeight - defaultBottom - footerHeight, left: defaultLeft, width: pageWidth - defaultLeft - defaultRight, height: footerHeight }
    const footerTitleRect: Rect = { top: footerRect.top - footerHeight, left: footerRect.left, width: footerRect.width, height: showFooterTitle ? footerHeight : 0, content: showFooterTitle ? footerTitle : '' }
    const footerLineRect: Rect = { top: footerRect.top, left: footerRect.left, width: footerRect.width, height: showFooterLine ? lineHeight : 0 }
    const printerRect: Rect = { top: footerRect.top + 2, left: footerRect.left, width: footerRect.width * 0.3, height: footerRect.height, content: showPrinter ? `打印者:${userObj.user_name ?? ''}` : '' }
    const dateRect: Rect = { top: footerRect.top + 2, left: footerRect.left + printerRect.width, width: footerRect.width * 0.4, height: footerRect.height, content: showDate ? `打印时间:${moment(new Date()).format('YYYY-MM-DD HH:mm:ss')}` : '' }
    const numRect: Rect = { top: footerRect.top + 2, left: footerRect.left + printerRect.width + dateRect.width + (footerRect.width * 0.3 - pageNumWidth * 2) - 2, width: pageNumWidth, height: footerRect.height, content: showPageNum ? '第#页' : '' }
    const sumRect: Rect = { top: footerRect.top + 2, left: numRect.left + numRect.width + 2, width: pageNumWidth, height: footerRect.height, content: showPageNum ? '共#页' : '' }

    const bodyRect: Rect = { top: 5 + headerRect.top + headerRect.height, left: defaultLeft, width: pageWidth - defaultLeft - defaultRight, height: pageHeight - (headerRect.top + headerRect.height + 3) - (footerRect.height + defaultBottom + 3) - (showFooterTitle ? footerHeight : 0) }
    const titleRect: TitleRect = { top: bodyRect.top, left: bodyRect.left, width: bodyRect.width, height: titleHeight, content: showTitle ? title : '', itemType: titleAllPrint ? 1 : 0 }
    const subTitleRect: Rect = { top: titleRect.top + titleRect.height + subTitleMarginTop, left: bodyRect.left, width: bodyRect.width, height: subTitleHeight }
    const subTitleRect1: TitleRect = { top: subTitleRect.top, left: subTitleRect.left, width: subTitleRect.width / (subTitleCount || 1), height: subTitleRect.height, content: showSubTitle ? subTitle[0] : undefined, itemType: subTitleAllPrint ? 1 : 0 }
    const subTitleRect2: TitleRect = { top: subTitleRect.top, left: subTitleCount <= 1 ? 0 : subTitleRect.left + (subTitleRect.width / subTitleCount), width: subTitleCount <= 1 ? 0 : subTitleRect.width / (subTitleCount || 1), height: subTitleRect.height, content: showSubTitle ? subTitle[1] : undefined, itemType: subTitleAllPrint ? 1 : 0 }
    const subTitleRect3: TitleRect = { top: subTitleRect.top, left: subTitleCount <= 2 ? 0 : subTitleRect.left + (subTitleRect.width / subTitleCount * (subTitleCount - 1)), width: subTitleCount <= 2 ? 0 : subTitleRect.width / (subTitleCount || 1), height: subTitleRect.height, content: showSubTitle ? subTitle[2] : undefined, itemType: subTitleAllPrint ? 1 : 0 }
    const tableRect: Rect = { top: subTitleRect.top + subTitleRect.height + 3, left: bodyRect.left, width: bodyRect.width, height: bodyRect.height - titleRect.height - subTitleRect.height - subTitleMarginTop - 9 }

    return {
        header: headerRect, logo: logoRect, headerLine: headerLineRect, headerTitle: headerTitleRect,
        body: bodyRect, title: titleRect, subTitle: subTitleRect, subTitle1: subTitleRect1, subTitle2: subTitleRect2, subTitle3: subTitleRect3,
        table: tableRect,
        footer: footerRect, footerLine: footerLineRect, footerTitle: footerTitleRect,
        printer: printerRect, date: dateRect, num: numRect, sum: sumRect
    }
}

// 计算每行放的个最大数
export const getMaxCount = (templateWidth: number, pageWidth: number, spacing: number): number => {
    let count = 1
    while ((count * templateWidth + (count - 1) * spacing) <= pageWidth) {
        count++
        if (count > 50) {
            break
        }
    }
    return (count - 1) || 1
}

// 解析base64内容构造标签模板
export const buildLabelTemplate = (templateContent: string): LabelTemplate => {
    const getParams = (dataStr: string): string[] => {
        const start = dataStr.indexOf('(') + 1
        const end = dataStr.lastIndexOf(')')
        const str = dataStr.substring(start, end)
        const params = str.split(',')
        return params.map(value => {
            const left = value.startsWith('"') ? value.substring(1) : value
            const right = left.endsWith('"') ? left.substring(0, left.length - 1) : left
            return right.replaceAll('\\"', '"').replaceAll('\\r', '').replaceAll('\\n', '')
        })
    }

    const getStyleParams = (dataStr: string): LabelPrintStyleParam => {
        const isNumber = (value: string): boolean => {
            return /^[0-9]+.?[0-9]*/.test(value)
        }
        const params = getParams(dataStr)
        const id = isNumber(params[0]) ? Number(params[0]) : params[0]
        const name = params[1]
        const value = isNumber(params[2]) ? Number(params[2]) : params[2]
        return [id, name, value]
    }

    const labelTemplate: LabelTemplate = {
        tempTop: new LabelNumber(0, 297),
        tempLeft: new LabelNumber(0, 210),
        tempWidth: new LabelNumber(0, 210),
        tempHeight: new LabelNumber(0, 297),
        labelTexts: [],
        labelHtmls: [],
        labelImages: [],
        labelTables: [],
        labelBarCodes: [],
        labelRects: [],
        labelEllipses: [],
        labelShapes: [],
        labelLines: []
    }

    const value = decode(templateContent)
    const tempDatas = value.split('LODOP')
    const exprs = [LabelCodeType.ADD_RECT, LabelCodeType.ADD_ELLIPSE, LabelCodeType.ADD_LINE]
    const initData = tempDatas.find(data => data.includes(LabelCodeType.INITA))!
    const initParams = getParams(initData)
    const tempWidth = new LabelNumber(initParams[2])
    const tempHeight = new LabelNumber(initParams[3])
    labelTemplate.tempTop = new LabelNumber(initParams[0])
    labelTemplate.tempLeft = new LabelNumber(initParams[1])
    labelTemplate.tempWidth = tempWidth
    labelTemplate.tempHeight = tempHeight

    for (let i = 0; i < tempDatas.length; i++) {
        const data = tempDatas[i]
        let j = i + 1
        const params = getParams(data)
        // 添加文本
        if (data.includes(LabelCodeType.ADD_TEXT)) {
            const styles: LabelPrintStyleParam[] = []
            while (tempDatas[j] && tempDatas[j].includes(LabelCodeType.SET_STYLE)) {
                const param = getStyleParams(tempDatas[j])
                styles.push(param)
                j++
            }
            const labelText: LabelText = data.includes(LabelCodeType.ADD_TEXTA) ? {
                fieldName: params[0],
                top: new LabelNumber(params[1], tempHeight.number),
                left: new LabelNumber(params[2], tempWidth.number),
                width: new LabelNumber(params[3], tempWidth.number),
                height: new LabelNumber(params[4], tempHeight.number),
                content: params[5],
                styles
            } : {
                top: new LabelNumber(params[0], tempHeight.number),
                left: new LabelNumber(params[1], tempWidth.number),
                width: new LabelNumber(params[2], tempWidth.number),
                height: new LabelNumber(params[3], tempHeight.number),
                content: params[4],
                styles
            }
            labelTemplate.labelTexts.push(labelText)
        }
        // 添加富文本和图片
        if (data.includes(LabelCodeType.ADD_HTML)) {
            const styles: LabelPrintStyleParam[] = []
            while (tempDatas[j] && tempDatas[j].includes(LabelCodeType.SET_STYLE)) {
                const param = getStyleParams(tempDatas[j])
                styles.push(param)
                j++
            }
            const fieldName = styles.find(([_id, name]) => name === 'ItemName')?.[2] as string | undefined
            const labelHtml: LabelHtml = {
                top: new LabelNumber(params[0], tempHeight.number),
                left: new LabelNumber(params[1], tempWidth.number),
                width: new LabelNumber(params[2], tempWidth.number),
                height: new LabelNumber(params[3], tempHeight.number),
                content: params[4],
                fieldName,
                styles
            }
            labelTemplate.labelHtmls.push(labelHtml)
        }
        // 添加图片
        if (data.includes(LabelCodeType.ADD_IMAGE)) {
            const styles: LabelPrintStyleParam[] = []
            while (tempDatas[j] && tempDatas[j].includes(LabelCodeType.SET_STYLE)) {
                const param = getStyleParams(tempDatas[j])
                styles.push(param)
                j++
            }
            const fieldName = styles.find(([_id, name]) => name === 'ItemName')?.[2] as string | undefined
            const labelImage: LabelImage = {
                top: new LabelNumber(params[0], tempHeight.number),
                left: new LabelNumber(params[1], tempWidth.number),
                width: new LabelNumber(params[2], tempWidth.number),
                height: new LabelNumber(params[3], tempHeight.number),
                url: params.slice(4).join(),
                fieldName,
                styles
            }
            labelTemplate.labelImages.push(labelImage)
        }
        // 添加表格
        if (data.includes(LabelCodeType.ADD_TABLE)) {
            const styles: LabelPrintStyleParam[] = []
            while (tempDatas[j] && tempDatas[j].includes(LabelCodeType.SET_STYLE)) {
                const param = getStyleParams(tempDatas[j])
                styles.push(param)
                j++
            }
            const fieldName = styles.find(([_id, name]) => name === 'ItemName')?.[2] as string | undefined
            const labelTable: LabelTable = {
                top: new LabelNumber(params[0], tempHeight.number),
                left: new LabelNumber(params[1], tempWidth.number),
                width: new LabelNumber(params[2], tempWidth.number),
                height: new LabelNumber(params[3], tempHeight.number),
                content: params.slice(4).join(),
                fieldName,
                styles
            }
            labelTemplate.labelTables.push(labelTable)
        }
        // 添加条码
        if (data.includes(LabelCodeType.ADD_BARCODE)) {
            const styles: LabelPrintStyleParam[] = []
            while (tempDatas[j] && tempDatas[j].includes(LabelCodeType.SET_STYLE)) {
                const param = getStyleParams(tempDatas[j])
                styles.push(param)
                j++
            }
            const labelBarCode: LabelBarCode = data.includes(LabelCodeType.ADD_BARCODEA) ? {
                fieldName: params[0],
                top: new LabelNumber(params[1], tempHeight.number),
                left: new LabelNumber(params[2], tempWidth.number),
                width: new LabelNumber(params[3], tempWidth.number),
                height: new LabelNumber(params[4], tempHeight.number),
                codeType: params[5],
                codeValue: params[6],
                styles
            } : {
                top: new LabelNumber(params[0], tempHeight.number),
                left: new LabelNumber(params[1], tempWidth.number),
                width: new LabelNumber(params[2], tempWidth.number),
                height: new LabelNumber(params[3], tempHeight.number),
                codeType: params[4],
                codeValue: params[5],
                styles
            }
            labelTemplate.labelBarCodes.push(labelBarCode)
        }
        // 添加其它图形
        if (data.includes(LabelCodeType.ADD_SHAPE)) {
            const labelShape: LabelShape = {
                shapeType: Number(params[0]),
                top: new LabelNumber(params[1], tempHeight.number),
                left: new LabelNumber(params[2], tempWidth.number),
                width: new LabelNumber(params[3], tempWidth.number),
                height: new LabelNumber(params[4], tempHeight.number),
                lineStyle: Number(params[5]),
                lineWidth: Number(params[6]),
                fillColor: params[7]
            }
            labelTemplate.labelShapes.push(labelShape)
        }
        // 添加图形
        const expr = exprs.find(expr => data.includes(expr))
        if (expr) {
            const label: LabelLine = {
                top: new LabelNumber(params[0], tempHeight.number),
                left: new LabelNumber(params[1], tempWidth.number),
                width: new LabelNumber(params[2], tempWidth.number),
                height: new LabelNumber(params[3], tempHeight.number),
                lineStyle: Number(params[4]),
                lineWidth: Number(params[5])
            }
            switch (expr) {
                case LabelCodeType.ADD_RECT:
                    labelTemplate.labelRects.push(label)
                    break
                case LabelCodeType.ADD_ELLIPSE:
                    labelTemplate.labelEllipses.push(label)
                    break
                case LabelCodeType.ADD_LINE:
                    labelTemplate.labelLines.push(label)
                    break
                default: break
            }
        }
    }
    return labelTemplate
}

// 设置模板内标签的数据，一页放一个模板
export const setLabelTemplateData = (labelTemplate: LabelTemplate, printData: any[], baseUrl?: string, tableColumn?: TableColumn): LabelTemplate[][] => {
    const { labelTexts, labelHtmls, labelImages, labelBarCodes, labelTables } = labelTemplate
    const labelDatas: LabelTemplate[][] = []
    for (let i = 0; i < printData.length; i++) {
        const tempTexts: LabelText[] = []
        const tempHtmls: LabelHtml[] = []
        const tempImages: LabelImage[] = []
        const tempTables: LabelTable[] = []
        const tempBarCodes: LabelBarCode[] = []
        const labelData = printData[i]
        const fields = Object.keys(labelData)
        labelTexts.forEach(text => {
            let content = text.content
            const field = fields.find(field => field === text.fieldName)
            if (field) {
                const data = labelData[field]
                if (data) {
                    if (content.includes(`[${field}]`)) {
                        content = content.replaceAll(`[${field}]`, data)
                    } else {
                        content = data
                    }
                }
            }
            tempTexts.push({ ...text, content })
        })

        labelHtmls.forEach(html => {
            let content = html.content
            const field = fields.find(field => field === html.fieldName)
            if (field) {
                const data = labelData[field]
                if (data) {
                    const info = data.info
                    if (info) {
                        const url = baseUrl ? (baseUrl + info[0].addr) : info[0].addr
                        content = `<img style="width:100%" src=${url} alt="" />`
                    } else if (typeof data === 'string') {
                        content = data.replaceAll('text-decoration-line', 'text-decoration')
                    } else {
                        content = data
                    }
                }
            }
            tempHtmls.push({ ...html, content })
        })

        labelImages.forEach(image => {
            let url = image.url
            const field = fields.find(field => field === image.fieldName)
            if (field) {
                const data = labelData[field]
                if (data) {
                    url = `<img style="width:100%" src=${data} alt="" />`
                }
            }
            tempImages.push({ ...image, url })
        })

        labelTables.forEach(table => {
            let content = table.content
            const field = fields.find(field => field === table.fieldName)
            if (field) {
                const data = labelData[field]
                if (typeof data !== 'string' && tableColumn) {
                    content = buildTableData(tableColumn[field], data)
                }
            }
            tempTables.push({ ...table, content })
        })

        labelBarCodes.forEach(barCode => {
            let codeValue = barCode.codeValue
            const field = fields.find(field => field === barCode.fieldName)
            if (field) {
                const data = labelData[field]
                if (data) {
                    codeValue = data
                }
            }
            tempBarCodes.push({ ...barCode, codeValue })
        })

        labelDatas.push([
            {
                ...labelTemplate,
                labelTexts: tempTexts,
                labelHtmls: tempHtmls,
                labelTables: tempTables,
                labelBarCodes: tempBarCodes,
            }
        ])
    }
    return labelDatas
}

// 设置模板内标签的数据，一页放多个模板
export const setLabelTemplateDataWithArrange = (labelTemplate: LabelTemplate, printData: any[], printerParam: PrinterParam, countOfPage: number, countOfColumn: number, baseUrl?: string): LabelTemplate[][] => {
    const labelCount = printData.length
    const { tempWidth, tempHeight, labelTexts, labelHtmls, labelImages, labelBarCodes, labelRects, labelEllipses, labelLines, labelShapes } = labelTemplate
    const { colSpacing, rowSpacing } = printerParam
    const pageParams: LabelPageParam[] = []
    for (let i = 0; i < labelCount; i++) {
        const labelData = printData[i]

        const tempTexts: LabelText[] = []
        const tempHtmls: LabelHtml[] = []
        const tempImages: LabelImage[] = []
        const tempBarCodes: LabelBarCode[] = []

        const tempShapes: LabelShape[] = []
        const tempRects: LabelRect[] = []
        const tempEllipses: LabelEllipse[] = []
        const tempLines: LabelLine[] = []

        const pageIndex = Math.floor(i / countOfPage)
        const column = i % countOfColumn
        const row = Math.floor(i % countOfPage / countOfColumn)
        const left = tempWidth.number * column + column * colSpacing
        const top = tempHeight.number * row + row * rowSpacing
        const fields = Object.keys(labelData)

        labelTexts.forEach(text => {
            let content = text.content
            const field = fields.find(field => field === text.fieldName)
            if (field) {
                const data = labelData[field]
                if (data) {
                    if (content.includes(`[${field}]`)) {
                        content = content.replaceAll(`[${field}]`, data)
                    } else {
                        content = data
                    }
                }
            }
            const textLeft = new LabelNumber(left + text.left.number)
            const textTop = new LabelNumber(top + text.top.number)
            tempTexts.push({ ...text, content, left: textLeft, top: textTop })
        })

        labelHtmls.forEach(html => {
            let content = html.content
            const field = fields.find(field => field === html.fieldName)
            if (field) {
                const data = labelData[field]
                if (data) {
                    const info = data.info
                    if (info) {
                        const url = baseUrl ? (baseUrl + info[0].addr) : info[0].addr
                        content = `<img style="width:100%" src=${url} alt="" />`
                    } else if (typeof data === 'string') {
                        content = data.replaceAll('text-decoration-line', 'text-decoration')
                    } else {
                        content = data
                    }
                }
            }
            const htmlLeft = new LabelNumber(left + html.left.number)
            const htmlTop = new LabelNumber(top + html.top.number)
            tempHtmls.push({ ...html, content, left: htmlLeft, top: htmlTop })
        })

        labelImages.forEach(image => {
            let url = image.url
            const field = fields.find(field => field === image.fieldName)
            if (field) {
                const data = labelData[field]
                if (url) {
                    url = `<img style="width:100%" src=${data} alt="" />`
                }
            }
            const imageLeft = new LabelNumber(left + image.left.number)
            const imageTop = new LabelNumber(top + image.top.number)
            tempImages.push({ ...image, url, left: imageLeft, top: imageTop })
        })

        labelBarCodes.forEach(barCode => {
            let codeValue = barCode.codeValue
            const field = fields.find(field => field === barCode.fieldName)
            if (field) {
                const data = labelData[field]
                if (data) {
                    codeValue = data
                }
            }
            const barCodeLeft = new LabelNumber(left + barCode.left.number)
            const barCodeTop = new LabelNumber(top + barCode.top.number)
            tempBarCodes.push({ ...barCode, codeValue, left: barCodeLeft, top: barCodeTop })
        })

        labelShapes.forEach(shape => {
            const shapeLeft = new LabelNumber(left + shape.left.number)
            const shapeTop = new LabelNumber(top + shape.top.number)
            tempShapes.push({ ...shape, left: shapeLeft, top: shapeTop })
        })

        labelEllipses.forEach(ellipse => {
            const ellipseLeft = new LabelNumber(left + ellipse.left.number)
            const ellipseTop = new LabelNumber(top + ellipse.top.number)
            tempEllipses.push({ ...ellipse, left: ellipseLeft, top: ellipseTop })
        })

        labelRects.forEach(rect => {
            const rectLeft = new LabelNumber(left + rect.left.number)
            const rectTop = new LabelNumber(top + rect.top.number)
            tempRects.push({ ...rect, left: rectLeft, top: rectTop })
        })

        labelLines.forEach(line => {
            const lineLeft = new LabelNumber(left + line.left.number)
            const lineTop = new LabelNumber(top + line.top.number)
            tempLines.push({ ...line, left: lineLeft, top: lineTop })
        })

        pageParams.push([pageIndex, {
            ...labelTemplate,
            tempTop: new LabelNumber(top),
            tempLeft: new LabelNumber(left),
            labelTexts: tempTexts,
            labelHtmls: tempHtmls,
            labelBarCodes: tempBarCodes,
            labelShapes: tempShapes,
            labelEllipses: tempEllipses,
            labelRects: tempRects,
            labelLines: tempLines
        }])
    }

    const pageIndexs = Array.from(new Set(pageParams.map(rect => rect[0])))
    const labelDatas: LabelTemplate[][] = []
    for (let i = 0; i < pageIndexs.length; i++) {
        const pageIndex = pageIndexs[i]
        const tempDatas: LabelTemplate[] = []
        for (let j = 0; j < pageParams.length; j++) {
            const pageParam = pageParams[j];
            const pageTemplate = pageParam[1]
            if (pageParam[0] === pageIndex) {
                tempDatas.push(pageTemplate)
            }
        }
        labelDatas.push(tempDatas)
    }
    return labelDatas
}

const buildTableData = (columnInfo: ColumnInfo, rowDatas: any[]) => {
    const { columns, statistics } = columnInfo
    columns.forEach(column => {
        const stastic = statistics?.find(stastic => stastic.field === column.name)
        column.statistics = stastic?.property
    })

    const div = document.createElement('div')
    const table = document.createElement('table')
    table.setAttribute('border', '1')
    table.setAttribute('cellSpacing', '0')
    table.setAttribute('width', '100%')
    table.setAttribute('style', 'border-collapse:collapse')
    table.setAttribute('bordercolor', '#333333')

    const thead = document.createElement('thead')
    const tr = document.createElement('tr')
    for (let i = 0; i < columns.length; i++) {
        const th = document.createElement('th')
        const column = columns[i]
        th.textContent = column.label
        tr.appendChild(th)
    }
    thead.appendChild(tr)
    table.appendChild(thead)

    const tbody = document.createElement('tbody')
    for (let i = 0; i < rowDatas.length; i++) {
        const row = rowDatas[i]
        const tr = document.createElement('tr')
        for (let j = 0; j < columns.length; j++) {
            const td = document.createElement('td')
            const column = columns[j]
            td.textContent = row[column.name]
            tr.appendChild(td)
        }
        tbody.appendChild(tr)
    }
    table.appendChild(tbody)

    if (statistics) {
        const tfoot = document.createElement('tfoot')
        const maxRow = statistics.map(item => item.property.length).sort((a, b) => b - a)?.[0] ?? 0
        for (let i = 0; i < maxRow; i++) {
            const tr = document.createElement('tr')
            for (let j = 0; j < columns.length; j++) {
                const column = columns[j]
                const statistic = column.statistics?.[i]
                const td = document.createElement('td')
                if (statistic) {
                    td.textContent = statistic.label
                    td.setAttribute('format', statistic.format)
                    td.setAttribute('tdata', statistic.tdata)
                }
                tr.appendChild(td)
            }
            tfoot.appendChild(tr)
        }
        table.appendChild(tfoot)
    }

    div.appendChild(table)
    return div.innerHTML
}

export const buildTableHtml = (tableStyle: OptionValues & { tableWidth: number }, tableColumns: ColumnDataType[], tableHeadRows: any[], tableData: any[], range: [number, number], isLastTask: boolean) => {
    const [start, end] = range
    const showColumns = tableColumns.filter(column => column.printType != 'none' && column.width != 0 && column.width != undefined)
    let width = 0
    let idx = showColumns.length
    for (let i = 0; i < showColumns.length; i++) {
        const column = showColumns[i]
        width += column.width!
        if (width > tableStyle.tableWidth) {
            idx = i
            break
        }
    }
    const columns = showColumns.slice(0, idx)
    const hasStatistic = columns.some(column => column.statistic != 'none')
    const wrap = document.createElement('div')
    const div = document.createElement('div')
    div.setAttribute('style', `text-align: center; overflow: hidden`)
    const table = document.createElement('table')
    table.setAttribute('border', tableStyle.lineWidth.toString())
    table.setAttribute('cellSpacing', '0')
    table.setAttribute('style', `font-size: 13px; width: ${width}px; border-collapse:collapse; margin: 0 auto; border: ${tableStyle.borderWidth}px solid; table-layout: fixed;`)
    table.setAttribute('bordercolor', '#333333')

    const colgroup = document.createElement('colgroup')
    columns.forEach(column => {
        const col = document.createElement('col')
        if (column.width) {
            col.style.setProperty('width', `${column.width * 3.78}px`)
        }
        colgroup.appendChild(col)
    })
    table.appendChild(colgroup)

    const thead = document.createElement('thead')
    thead.setAttribute('style', 'display: table-header-group')

    for (let i = 0; i < tableHeadRows.length; i++) {
        const headRow = tableHeadRows[i]
        const tr = document.createElement('tr')
        headRow.forEach((item: any) => {
            const temp = item.rowspan == tableHeadRows.length - i

            const th = document.createElement('th')
            th.textContent = temp ? item.column.label : item.label
            th.setAttribute('colspan', item.colspan.toString())
            th.setAttribute('rowspan', item.rowspan.toString())

            tr.appendChild(th)
        })
        thead.appendChild(tr)
    }
    table.appendChild(thead)

    const sortColumnNames = flatMap(columns ?? [], column => column.sort != 'none' ? { name: column.name, func: column.sort } : [])
    const tbody = document.createElement('tbody')

    const data = sortArray(tableData.slice(start, end), sortColumnNames)
    for (let i = 0; i < data.length; i++) {
        const row = data[i]
        const tr = document.createElement('tr')
        for (let j = 0; j < columns.length; j++) {
            const td = document.createElement('td')
            const column = columns[j]
            const value = getCellValue(row[column.name], column)
            td.textContent = value
            td.setAttribute('style', `white-space: pre-line; word-wrap: break-word; text-align: ${column.align || 'left'}; padding: ${tableStyle.rowPadding * 3.78}px ${tableStyle.colPadding * 3.78}px ; `)
            tr.appendChild(td)
        }
        tbody.appendChild(tr)
    }

    const dataTypeArr = ['number', 'static-number', 'input-number', 'progress', 'static-progress']
    if (isLastTask && !tableStyle.countAllPage && hasStatistic) {
        const tr = document.createElement('tr')
        for (let j = 0; j < columns.length; j++) {
            const td = document.createElement('td')
            if (j == 0) {
                td.textContent = '合计:'
            }
            const column = columns[j]
            if (column.statistic == 'Sum') {
                if (dataTypeArr.includes(column.type) || column.pristine.isNumerical) {
                    const value = calcFn('sum', column.name, tableData)
                    td.textContent = getCellValue(value, column)
                } else {
                    const value = data.filter(item => item[column.name]).length
                    td.textContent = value.toString()
                }
                td.setAttribute('style', `white-space: pre-line; word-wrap: break-word; text-align: ${column.align || 'left'}`)
            }
            tr.appendChild(td)
        }
        tbody.appendChild(tr)
    }

    table.appendChild(tbody)

    if (tableStyle.countAllPage && hasStatistic) {
        const tfoot = document.createElement('tfoot')
        const tr = document.createElement('tr')
        columns.forEach((column, index) => {
            const td = document.createElement('td')
            if (index == 0) {
                td.textContent = '合计:'
            }
            if (column.statistic == 'Sum') {
                if (dataTypeArr.includes(column.type) || column.pristine.isNumerical) {
                    const value = calcFn('sum', column.name, tableData)
                    td.textContent = getCellValue(value, column)
                } else {
                    const value = data.filter(item => item[column.name]).length
                    td.textContent = value.toString()
                }
                td.setAttribute('style', `white-space: pre-line; word-wrap: break-word; text-align: ${column.align || 'left'}`)
            }

            tr.appendChild(td)
        })
        tfoot.appendChild(tr)
        table.append(tfoot)
    }

    div.appendChild(table)
    wrap.appendChild(div)
    return wrap.innerHTML
}

const sortArray = (datas: any[], columns: { name: string, func: 'asc' | 'desc' }[]) => {
    if (columns.length > 0) {
        const column = columns.pop()
        if (column) {
            const name = column.name
            const func = column.func
            datas = datas.sort((a, b) => {
                const valueA = a[name]
                const valueB = b[name]
                return sortFn(valueA, valueB, func)
            })
            sortArray(datas, columns)
        }
    }
    return datas
}