<template>
    <div class="_fd-print">
        <el-tooltip
            effect="dark"
            :content="t('designer.print.title')"
            placement="top"
            :hide-after="0"
        >
            <i class="fc-icon icon-print" @click="open"></i>
        </el-tooltip>
        <el-dialog class="_fd-print-dialog _fd-config-dialog" v-model="visible" destroy-on-close
                   :close-on-click-modal="false"
                   :title="t('designer.print.title')"
                   append-to-body
                   width="1080px">
            <el-container class="_fd-print-con" style="height: 600px">
                <el-aside style="width:255px;">
                    <el-container class="_fd-print-l">
                        <el-header class="_fd-print-head" height="40px">
                            {{ t('designer.print.config') }}
                        </el-header>
                        <el-main>
                            <el-form label-position="top" size="small">
                                <el-form-item :label="t('props.mode')">
                                    <el-radio-group v-model="formData.type">
                                        <el-radio-button value="form">{{ t('form.formMode') }}</el-radio-button>
                                        <el-radio-button value="read">{{ t('form.previewMode') }}</el-radio-button>
                                    </el-radio-group>
                                </el-form-item>
                                <el-form-item :label="t('props.style')">
                                    <el-radio-group v-model="formData.style">
                                        <el-radio-button value="default">{{
                                                t('designer.print.defaultStyle')
                                            }}
                                        </el-radio-button>
                                        <el-radio-button value="word">{{
                                                t('designer.print.wordStyle')
                                            }}
                                        </el-radio-button>
                                    </el-radio-group>
                                </el-form-item>
                                <el-form-item :label="t('style.width')">
                                    <el-input-number :min="300" controls-position="right"
                                                     v-model="formData.width"></el-input-number>
                                </el-form-item>
                                <template v-for="item in padding" :key="item">
                                    <el-form-item :label="t('designer.print.' + item)">
                                        <el-input-number :min="0" controls-position="right"
                                                         v-model="formData[item]"></el-input-number>
                                    </el-form-item>
                                </template>
                            </el-form>
                        </el-main>
                    </el-container>
                </el-aside>
                <el-main>
                    <el-container class="_fd-print-r">
                        <el-main>
                            <ViewForm class="_fd-print-form" :class="{'_fd-print-form-word': formData.style === 'word'}"
                                      ref="form" :rule="rule" :option="options"
                                      v-if="visible"
                                      :style="{width: formData.width > 0 ? (formData.width + 'px') : '100%'}">
                                <template v-for="(_, name) in $slots" #[name]="scope">
                                    <slot :name="name" v-bind="scope ?? {}"/>
                                </template>
                            </ViewForm>
                        </el-main>
                    </el-container>
                </el-main>
            </el-container>
            <template #footer>
                <div>
                    <el-button size="default" @click="visible=false">{{ t('props.cancel') }}</el-button>
                    <el-button size="default" @click="print(true)">{{
                            t('designer.print.export')
                        }}</el-button>
                    <el-button type="primary" size="default" @click="print(false)" :loading="printing">{{ t('props.print') }}
                    </el-button>
                </div>
            </template>
        </el-dialog>
    </div>
</template>

<script>
import {defineComponent, markRaw} from 'vue';
import Warning from './Warning.vue';
import viewForm from '../utils/form';
import loadjs from '../utils/loadjs/loadjs';
import SizeInput from './style/SizeInput.vue';

export default defineComponent({
    name: 'PrintForm',
    components: {
        SizeInput,
        Warning,
        ViewForm: viewForm.$form(),
    },
    inject: ['designer'],
    data() {
        return {
            visible: false,
            printing: false,
            frame: null,
            rule: [],
            options: {},
            padding: ['top', 'bottom', 'left', 'right'],
            formData: {
                type: 'form',
                style: 'default',
                left: 20,
                right: 20,
                top: 20,
                bottom: 20,
                width: 780,
            },
        };
    },
    computed: {
        t() {
            return this.designer.setupState.t;
        },
    },
    watch: {
        visible(v) {
            if (v) {
                this.rule = viewForm.parseJson(this.designer.setupState.getPreviewRule());
                this.options = viewForm.parseJson(this.designer.setupState.getOptionsJson());
                this.options.submitBtn = false;
                this.options.resetBtn = false;
            } else {
                this.printing = false;
                if (this.frame) {
                    document.body.removeChild(this.frame);
                    this.frame = null;
                }
            }
        },
        'formData.type': function (n) {
            this.options.preview = n === 'read';
        }
    },
    methods: {
        open() {
            this.visible = true;
        },
        disableImageSmoothing(ctx) {
            ctx.imageSmoothingEnabled = false;
            ctx.mozImageSmoothingEnabled = false;
            ctx.webkitImageSmoothingEnabled = false;
            ctx.msImageSmoothingEnabled = false;
        },
        print(flag) {
            this.printing = true;
            loadjs.ready(['html2canvas', 'jspdf'], () => {
                window.html2canvas(this.$refs.form.$el, {
                    allowTaint: true,
                    useCORS: true,
                }).then((canvas) => {
                    const pdf = new window.jspdf.jsPDF({
                        orientation: 'p',
                        unit: 'pt',
                        format: 'a4',
                    });

                    this.disableImageSmoothing(canvas.getContext('2d'));

                    const {
                        left: marginLeft,
                        right: marginRight,
                        top: marginTop,
                        bottom: marginBottom,
                    } = this.formData;

                    const pageWidth = pdf.internal.pageSize.getWidth();
                    const pageHeight = pdf.internal.pageSize.getHeight();
                    const contentWidth = pageWidth - marginLeft - marginRight;
                    const contentHeight = pageHeight - marginTop - marginBottom;

                    const scaledHeight = (canvas.height * contentWidth) / canvas.width;

                    if (scaledHeight <= contentHeight) {
                        pdf.addImage(
                            canvas.toDataURL('image/jpeg'),
                            'JPEG',
                            marginLeft,
                            marginTop,
                            contentWidth,
                            scaledHeight
                        );
                    } else {
                        let remainingHeight = scaledHeight;
                        let page = 0;
                        const clipHeight = canvas.width * contentHeight / contentWidth;

                        while (remainingHeight > 0) {
                            const tempCanvas = document.createElement('canvas');
                            const tempCtx = tempCanvas.getContext('2d');
                            this.disableImageSmoothing(tempCtx);

                            const offsetY = page * clipHeight;
                            const actualClipHeight = Math.min(clipHeight, canvas.height - offsetY);

                            tempCanvas.width = canvas.width;
                            tempCanvas.height = actualClipHeight;

                            tempCtx.drawImage(
                                canvas,
                                0, offsetY, canvas.width, actualClipHeight,
                                0, 0, canvas.width, actualClipHeight
                            );

                            const imageHeight = (actualClipHeight / canvas.height) * scaledHeight;

                            pdf.addImage(
                                tempCanvas.toDataURL('image/jpeg'),
                                'JPEG',
                                marginLeft,
                                marginTop,
                                contentWidth,
                                imageHeight
                            );

                            remainingHeight -= contentHeight;
                            if (remainingHeight > 0) {
                                pdf.addPage();
                                page++;
                            }
                        }
                    }
                    if (flag) {
                        this.printing = false;
                        window.open(URL.createObjectURL(pdf.output('blob')));
                    } else {
                        this.printPdf(pdf);
                    }
                }).catch((e) => {
                    this.printing = false;
                });
            });
        },
        printPdf(pdf) {
            if (!this.frame) {
                const frame = markRaw(document.createElement('iframe'));
                frame.style.width = '0';
                frame.style.position = 'absolute';
                frame.style.height = '0';
                frame.style.border = 'none';
                frame.onload = function () {
                    setTimeout(() => {
                        frame.contentWindow.print();
                    }, 100);
                }
                document.body.appendChild(frame);
                this.frame = frame;
            }
            this.frame.src = URL.createObjectURL(pdf.output('blob'));
            this.printing = false;
        },
    },
    created() {
        if (window.html2canvas) {
            loadjs.done('html2canvas');
        } else if (!loadjs.isDefined('html2canvas')) {
            loadjs.loadNpm('html2canvas@1.4.1/dist/html2canvas.min.js', 'html2canvas');
        }
        if (window.jspdf) {
            loadjs.done('jspdf');
        } else if (!loadjs.isDefined('jspdf')) {
            loadjs.loadNpm('jspdf@3.0.1/dist/jspdf.umd.js', 'jspdf');
        }
    }
});
</script>

<style>
._fd-print .el-button {
    font-weight: 400;
    width: 100%;
}

._fd-print-con .el-main {
    padding: 0;
}

._fd-print-l, ._fd-print-r {
    display: flex;
    flex-direction: column;
    flex: 1;
    height: 100%;
    border: 1px solid var(--fc-line-color-3);
}

._fd-print-head {
    display: flex;
    padding: 5px 15px;
    border-bottom: 1px solid var(--fc-line-color-3);
    background: var(--fc-bg-color-3);
    align-items: center;
}

._fd-print-head .el-button.is-link {
    color: var(--fc-style-color-1);
}

._fd-print-r {
    border-left: 0 none;
}

._fd-print-r ._fd-print-head {
    justify-content: flex-end;
}

._fd-print-l > .el-main, ._fd-print-r > .el-main {
    display: flex;
    flex-direction: column;
    flex: 1;
    flex-basis: auto;
    box-sizing: border-box;
    min-width: 0;
    width: 100%;
    padding: 10px;
}

._fd-print-l .el-form .el-radio-group, ._fd-print-l .el-form .el-radio-button__inner {
    width: 100%;
}

._fd-print-l .el-form .el-radio-button {
    flex: 1;
}

._fd-print-r > .el-main {
    flex-direction: column;
    padding: 20px;
    position: relative;
}

._fd-print-form {
    padding: 2px;
    box-sizing: border-box;
}

._fd-print-form .el-input__wrapper, ._fd-print-form .el-textarea__inner, ._fd-print-form .el-select__wrapper {
    box-shadow: none !important;
    border: 1px solid var(--el-input-border-color, var(--el-border-color));
}

._fd-print-form .el-select__placeholder {
    position: unset !important;
    top: unset !important;
    transform: unset !important;
}

._fd-print-form .is-disabled .el-input__wrapper {
    background-color: unset !important;
}

._fd-print-form .is-disabled .el-input__inner {
    color: unset !important;
}

._fd-print-form-word .el-input__wrapper, ._fd-print-form-word .el-textarea__inner, ._fd-print-form-word .el-select__wrapper {
    border: none !important;
    border-bottom: 1px solid var(--el-input-border-color, var(--el-border-color)) !important;
    border-color: inherit !important;
    border-radius: 0 !important;
}

._fd-print-form-word .el-input-number__decrease, ._fd-print-form-word .el-input-number__increase {
    display: none !important;
}

._fd-print-form-word ._fc-read-view {
    display: block;
    width: 100%;
    height: 1.5em;
    padding: 0 4px;
    line-height: 1.5em;
    border-bottom: 1px solid var(--el-input-border-color, var(--el-border-color)) !important;
    border-color: inherit !important;
}

._fd-print-page-line {
    position: absolute;
    border-bottom: 1px dashed var(--fc-line-color-3);
    left: 0;
    right: 0;
    height: 1px;
    color: var(--fc-text-color-3);
    padding-left: 4px;
    box-sizing: border-box;
    font-size: 12px;
    line-height: 2em;
    z-index: 1;
}

</style>
