<template>
    <div class="_fc-infinite-table-form" :class="{'_fc-disabled': disabled}">
        <component :is="Form" :option="options" :rule="rule" :extendOption="true"
                   @change="formChange"
                   :disabled="disabled"
                   v-model:api="fapi"
                   @emit-event="$emit"></component>
        <el-button link type="primary" class="fc-clock" v-if="!max || max > this.trs.length"
                   @click="addRaw(true)"><i class="fc-icon icon-add-circle" style="font-weight: 700;"></i>
            {{ formCreateInject.t('add') || '添加' }}
        </el-button>
    </div>
</template>

<script>
import {markRaw, reactive} from 'vue';
import {deepCopy} from '@form-create/utils/lib/deepextend';
import {hasProperty} from '@form-create/utils/lib/type';

export default {
    name: 'InfiniteTableForm',
    emits: ['change', 'add', 'delete', 'update:modelValue'],
    props: {
        formCreateInject: Object,
        modelValue: {
            type: Array,
            default: () => [],
        },
        columns: {
            type: Array,
            required: true,
            default: () => []
        },
        options: {
            type: Object,
            default: () => reactive(({
                submitBtn: false,
                resetBtn: false,
            }))
        },
        max: Number,
        layerMax: {
            type: Number,
            default: 0,
        },
        childrenField: String,
        disabled: Boolean,
    },
    computed: {
        preview() {
            return this.formCreateInject.preview;
        },
        subField() {
            return this.childrenField || 'children';
        },
    },
    watch: {
        modelValue() {
            this.updateTable()
        },
        'formCreateInject.preview'(n) {
            this.trs.forEach((tr, i) => {
                if (tr.children[1]) {
                    tr.children[1].children[0].props.colspan = this.rule[0].children[0].children[0].children.length - (n ? 1 : 0);
                }
                tr.children[0].children[0].children[0].hidden = this.layerMax === 1 || n && !(this.modelValue && this.modelValue[i] && Array.isArray(this.modelValue[i][this.subField]) && this.modelValue[i][this.subField].length > 0);
            });
        },
    },
    data() {
        return {
            rule: [],
            trs: [],
            fapi: {},
            Form: markRaw(this.formCreateInject.form.$form()),
            copyTrs: '',
            oldValue: ''
        };
    },
    methods: {
        formChange(field, _, rule, api, flag) {
            if (false === flag) {
                this.updateValue();
            }
        },
        updateValue() {
            const value = this.trs.map((tr, idx) => {
                const formData = {
                    ...(this.modelValue[idx] || {}),
                    ...this.fapi.getChildrenFormData(tr)
                }
                if (!hasProperty(formData, this.subField) && this.modelValue[idx]) {
                    formData[this.subField] = this.modelValue[idx][this.subField];
                }
                if (formData[this.subField] == null) {
                    delete formData[this.subField];
                }
                return formData;
            });
            const str = JSON.stringify(value);
            if (str !== this.oldValue) {
                this.oldValue = str;
                this.$emit('update:modelValue', value);
                this.$emit('change', value);
            }
        },
        setRawData(idx, formData) {
            const raw = this.trs[idx];
            this.fapi.setChildrenFormData(raw, formData, true);
        },
        updateTable() {
            const str = JSON.stringify(this.modelValue);
            if (this.oldValue === str) {
                return;
            }
            this.oldValue = str;
            this.trs = this.trs.splice(0, this.modelValue.length);
            if (!this.modelValue.length) {
                this.addRaw();
            }
            this.modelValue.forEach((data, idx) => {
                if (!this.trs[idx]) {
                    this.addRaw();
                }
                this.setRawData(idx, data || {});
            });
            this.rule[0].children[1].children = this.trs;
        },
        delRaw(idx) {
            if (this.disabled) {
                return;
            }
            this.trs.splice(idx, 1);
            this.updateValue();
            if (this.trs.length) {
                this.trs.forEach(tr => this.updateRaw(tr));
            } else {
                this.addRaw();
            }
            this.$emit('delete', idx);
        },
        addRaw(flag) {
            if (flag && this.disabled) {
                return;
            }
            const tr = this.formCreateInject.form.parseJson(this.copyTrs)[0];
            const template = {
                type: 'template',
                subRule: true,
                children: []
            };
            template.children.push(tr);
            this.trs.push(template);
            this.trs.forEach(tr => this.updateRaw(tr));
            flag && this.$emit('add', this.trs);
        },
        updateRaw(tr) {
            const idx = this.trs.indexOf(tr);
            const row = tr.children[0];
            row.children[0].children[0].hidden = this.layerMax === 1 || this.preview && !(this.modelValue && this.modelValue[idx] && Array.isArray(this.modelValue[idx][this.subField]) && this.modelValue[idx][this.subField].length > 0);
            row.children[0].children[0].props.onClick = (inject) => {
                if (this.trs[idx].children.length === 1) {
                    if (this.disabled && !(this.modelValue && this.modelValue[idx] && Array.isArray(this.modelValue[idx][this.subField]) && this.modelValue[idx][this.subField].length > 0)) {
                        return;
                    }
                    this.trs[idx].children.push({
                        type: 'tr',
                        native: true,
                        display: true,
                        children: [{
                            type: 'td',
                            native: true,
                            props: {
                                colspan: this.rule[0].children[0].children[0].children.length - (this.preview ? 1 : 0),
                            },
                            class: '_fc-itf-sub',
                            children: [{
                                type: 'infiniteTableForm',
                                field: this.subField,
                                value: [...((this.modelValue[idx] && this.modelValue[idx][this.subField]) || [])],
                                props: {
                                    disabled: this.disabled,
                                    layerMax: this.layerMax === 0 ? 0 : (this.layerMax > 1 ? this.layerMax - 1 : 1),
                                    max: this.max || 0,
                                    columns: deepCopy(this.columns),
                                    options: deepCopy(this.options),
                                }
                            }]
                        }]
                    });
                }
                const icon = inject.self.children[0] === '-' ? '+' : '-';
                inject.self.children = [icon];
                this.trs[idx].children[1].display = icon === '-';
            };
            row.children[1].props.innerText = idx + 1;
            row.children[row.children.length - 1].children[0].props.onClick = () => {
                this.delRaw(idx);
            };
        },

        loadRule() {
            const header = [{
                type: 'th',
                native: true,
                class: '_fc-itf-sub-idx',
            }, {
                type: 'th',
                native: true,
                class: '_fc-itf-head-idx',
                props: {
                    innerText: '#'
                }
            }];
            let body = [{
                type: 'td',
                class: '_fc-itf-idx',
                native: true,
                children: [
                    {
                        type: 'div',
                        hidden: false,
                        children: ['+'],
                        inject: true,
                        props: {}
                    },
                ]
            }, {
                type: 'td',
                class: '_fc-itf-idx',
                native: true,
                props: {
                    innerText: '0'
                }
            }];
            this.columns.forEach((column) => {
                header.push({
                    type: 'th',
                    native: true,
                    class: column.required ? '_fc-itf-head-required' : '',
                    style: column.style,
                    props: {
                        innerText: column.label || ''
                    }
                });
                body.push({
                    type: 'td',
                    native: true,
                    children: [...(column.rule || [])]
                });
            });
            header.push({
                type: 'th',
                native: true,
                class: '_fc-itf-edit fc-clock',
                props: {
                    innerText: this.formCreateInject.t('operation') || '操作'
                }
            });
            body.push({
                type: 'td',
                native: true,
                class: '_fc-itf-btn fc-clock',
                children: [
                    {
                        type: 'i',
                        native: true,
                        class: 'fc-icon icon-delete',
                        props: {},
                    }
                ],
            });
            this.copyTrs = this.formCreateInject.form.toJson([
                {
                    type: 'tr',
                    native: true,
                    children: body
                }
            ]);
            this.rule = [
                {
                    type: 'table',
                    native: true,
                    class: '_fc-itf-table',
                    props: {
                        border: '1',
                        cellspacing: '0',
                        cellpadding: '0',
                    },
                    children: [
                        {
                            type: 'thead',
                            native: true,
                            children: [
                                {
                                    type: 'tr',
                                    native: true,
                                    children: header
                                }
                            ]
                        },
                        {
                            type: 'tbody',
                            native: true,
                            children: this.trs
                        }
                    ]
                }
            ]
        },
    },
    created() {
        this.loadRule();
    },
    mounted() {
        this.updateTable();
    }
};
</script>

<style>
._fc-infinite-table-form {
    overflow: auto;
    color: var(--fc-text-color-2);
}

._fc-infinite-table-form .form-create .el-form-item {
    margin-bottom: 1px;
}

._fc-infinite-table-form .form-create .el-form-item.is-error {
    margin-bottom: 22px;
}

._fc-infinite-table-form .el-form-item__label, ._fc-infinite-table-form .van-field__label {
    display: none !important;
}

._fc-infinite-table-form .el-form-item__content {
    display: flex;
    margin-left: 0px !important;
    width: 100% !important;
}

._fc-itf-table ._fc-itf-head-idx, ._fc-itf-table ._fc-itf-idx {
    width: 40px;
    min-width: 40px;
    font-weight: 500;
    text-align: center;
    padding: 0;
}

._fc-itf-idx div {
    display: inline-flex;
    justify-content: center;
    width: 18px;
    height: 18px;
    line-height: 16px;
    border: 1px solid #bfbfbf;
    border-radius: 6px;
    cursor: pointer;
}

._fc-itf-sub-idx {
    width: 30px;
}

._fc-itf-edit, ._fc-itf-btn {
    width: 70px;
    min-width: 70px;
    text-align: center;
}

._fc-itf-btn .fc-icon {
    cursor: pointer;
}

._fc-infinite-table-form._fc-disabled ._fc-itf-btn .fc-icon, ._fc-infinite-table-form._fc-disabled > .el-button {
    cursor: not-allowed;
}

._fc-itf-table {
    width: 100%;
    height: 100%;
    overflow: hidden;
    table-layout: fixed;
    border: 1px solid #EBEEF5;
    border-bottom: 0 none;
}

._fc-itf-table > thead > tr > th {
    border: 0 none;
    border-bottom: 1px solid #EBEEF5;
    height: 40px;
    font-weight: 500;
}

._fc-itf-table ._fc-itf-table > thead {
    display: none;
}

._fc-itf-table ._fc-itf-table {
    border-right: 0 none;
}

._fc-itf-table > thead > tr > th + th {
    border-left: 1px solid #EBEEF5;
}

._fc-itf-table tr {
    min-height: 50px;
}

._fc-itf-table ._fc-read-view {
    text-align: center;
    width: 100%;
}

._fc-itf-table td {
    padding: 10px;
    min-height: 50px;
    min-width: 80px;
    position: relative;
    box-sizing: border-box;
    overflow-wrap: break-word;
    /*white-space: nowrap;*/
    overflow: hidden;
    border: 0 none;
    border-bottom: 1px solid #EBEEF5;
}

._fc-itf-table td + td {
    border-left: 1px solid #EBEEF5;
}

._fc-itf-table .el-input-number, ._fc-itf-table .el-select, ._fc-itf-table .el-slider, ._fc-itf-table .el-cascader, ._fc-itf-table .el-date-editor {
    width: 100%;
}

._fc-infinite-table-form ._fc-itf-sub {
    padding: 5px 0 5px 10px;
}

._fc-itf-sub ._fc-table-form {
    background-color: var(--fc-bg-color-1);
}

._fc-itf-sub ._fc-tf-table {
    border: 0 none;
}

/*._fc-itf-sub ._fc-tf-table thead {
    background: #fafafa;
}*/

._fc-itf-sub-idx + ._fc-itf-head-idx, ._fc-itf-idx + ._fc-itf-idx {
    border-left: 0 none;
}

._fc-itf-head-required:before {
    content: '*';
    color: #f56c6c;
    margin-right: 4px;
}
</style>
