import { Prop, Vue, Watch } from 'vue-property-decorator';
import { CreateElement, VNode, VNodeData } from 'vue';
import sortable from 'sortablejs';
import { clone, mergeDeepRight } from 'ramda';
import { IDesignDefaultContext } from '../../interface';
import { GlobalService, IParams, IEntityLocalDataService } from '@ibizstudio/api';
import { generateOrderValue } from 'qx-util';
import { Modal } from 'ant-design-vue';
import { Util } from '@ibizstudio-ex/runtime';
import './design-item-base.less';

/**
 * 中部设计区项基类
 *
 * @export
 * @class DesignItemBase
 * @extends {Vue}
 */
export class DesignItemBase extends Vue {
    /**
     * 设计上下文
     *
     * @type {IDesignContext}
     * @memberof DesignItemBase
     */
    @Prop()
    ctx!: IDesignDefaultContext;
    ctrl!: IDesignDefaultContext['ctrl'];
    globalService!: GlobalService;

    /**
     * 当前容器dom实例
     *
     * @type {HTMLDivElement}
     * @memberof DesignItemBase
     */
    el!: HTMLDivElement;

    /**
     * 数据
     *
     * @type {any[]}
     * @memberof DesignItemBase
     */
    list: any[] = [];

    ctrlCtrl: any;
    context: any;

    /**
     * 当前是否为激活状态
     *
     * @memberof DesignItemBase
     */
    get active() {
        return this.data?.srfkey === this.ctrl?.select.data?.srfkey;
    }

    /**
     * 拖拽参数
     *
     * @type {sortable.Options}
     * @memberof DesignMaterialPanelBase
     */
    options: sortable.Options = {};

    /**
     * 项数据
     *
     * @type {any}
     * @memberof DesignItemBase
     */
    @Prop()
    data!: any;
    @Watch('data', { deep: true, immediate: true })
    dataWatch(newVal: any, oldVal: any): void {
        this.dataChange(newVal, oldVal);
    }

    /**
     * 父数据
     *
     * @type {any}
     * @memberof DesignItemBase
     */
    @Prop()
    parentData!: any;

    @Watch('parentData', { deep: true, immediate: true })
    parentDataChange(newVal: any, old: any) {
        this.$forceUpdate();
    }

    /**
     * 当前设计对象数据服务
     *
     * @type {IEntityLocalDataService<any>}
     * @memberof DesignItemBase
     */
    service!: IEntityLocalDataService<any>;

    /**
     * 当前预览设计对象数据服务
     *
     * @type {IEntityLocalDataService<any>}
     * @memberof DesignItemBase
     */
    previewService!: IEntityLocalDataService<any>;

    /**
     * 是否禁用消息中心通知
     *
     * @memberof DesignItemBase
     */
    isAcc = true;

    /**
     * 启用应用消息订阅
     *
     * @memberof DesignItemBase
     */
    enableAcc(): void {
        this.isAcc = true;
    }

    /**
     * 禁用应用消息订阅
     *
     * @memberof DesignItemBase
     */
    disableAcc(): void {
        this.isAcc = false;
    }

    initOption(): void {
        this.options = {
            handle: '.drag-handle',
            group: {
                name: this.ctx.tag,
            },
            animation: 150,
        };
    }

    /**
     * 数据变更
     *
     * @param {any} _newVal
     * @param {any} _oldData
     * @memberof DesignItemBase
     */
    dataChange(_newVal: any, _oldData: any): void {}

    /**
     * 组件创建完毕
     *
     * @memberof DesignItemBase
     */
    componentCreated(): void {}
    private created(): void {
        if (!this.ctx) {
            console.error('未设置上下文「ctx」，初始化异常!', this);
            return;
        }
        this.ctrl = this.ctx.ctrl;
        this.globalService = this.ctx.gs;
        this.initOption();
        this.selectChange = this.selectChange.bind(this);
        this.ctrl.select.evt.on('change', this.selectChange);
        this.componentCreated();
    }

    /**
     * 组件加载完毕
     *
     * @memberof DesignItemBase
     */
    componentMounted(): void {}
    private mounted(): void {
        this.el = this.$refs.designItem as any;
        this.options = mergeDeepRight(this.options, this.generateOption()) as any;
        this.ctrlCtrl = (this.ctrl.ctx.ctrl as any).ctrlCtrl;
        this.context = Util.deepCopy((this.ctrl.ctx as any).context);
        this.componentMounted();
    }

    /**
     * 组件销毁
     *
     * @memberof DesignItemBase
     */
    componentDestroyed(): void {}
    private destroyed(): void {
        this.ctrl.select.evt.off('change', this.selectChange);
        this.componentDestroyed();
    }

    /**
     * 查询数据
     *
     * @param {IParams} [params]
     * @return {*}  {Promise<any[]>}
     * @memberof DesignItemBase
     */
    async loadChild(params?: IParams): Promise<any[]> {
        if (this.previewService) {
            const arr = await this.previewService.selectLocal(this.ctx.context, params!);
            if (arr) {
                this.list.splice(0, this.list.length);
                this.list.push(...arr);
            }
            return arr;
        }
        console.warn('未设置当前设计对象所属服务', this);
        return [];
    }

    /**
     * 生成拖拽参数
     *
     * @return {*}  {sortable.Options}
     * @memberof DesignItemBase
     */
    generateOption(): sortable.Options {
        return {};
    }

    /**
     * 绘制内容
     *
     * @param {CreateElement} _h
     * @return {*}  {VNode[]}
     * @memberof DesignItemBase
     */
    renderContentList(_h: CreateElement): VNode[] {
        throw new Error('「renderContentList」此方法必须重写实现!');
    }

    /**
     * 设置选中数据
     *
     * @param {*} data
     * @memberof DesignItemBase
     */
    setSelect(data: any): void {
        if (this.ctrl) {
            this.ctrl.select.set(data);
        }
    }

    /**
     * 选中数据变更
     *
     * @param {any} data
     * @memberof DesignItemBase
     */
    selectChange(data: any): void {
        this.activeChange(data as any);
    }

    /**
     * 激活数据变更
     *
     * @param {any} data
     * @memberof DesignItemBase
     */
    activeChange(data: any): void {}

    /**
     * 用户操作提示
     *
     * @param {any} data
     * @memberof DesignItemBase
     */
    userOperationTips(event: any) {
        if (event?.added) {
            const panelCtrl: any = (this.ctrl.ctx as any)?.panelCtrl || this.ctrl;
            if (panelCtrl.evt) {
                panelCtrl.evt.emit('resetLayout');
            }
        }
        let select: string = '';
        const modal: any = Modal.confirm({
            class: 'operation-tips',
            width: 720,
            centered: true,
            maskClosable: false,
            content: () => {
                return (
                    <div class="tips">
                        <div class="tips-title">
                            <span>新建布局</span>
                            <i class="ivu-icon ivu-icon-ios-close" on-click={() => onCancel()}/>
                        </div>
                        <div class="tips-content">
                            <span class="tips-info">当前为默认布局无法编辑，是否进行自定义布局</span>
                            <div class="select-area">
                                <div class={{'tips-item': true, 'selected': Object.is(select, 'cloneDefaultLayoutNew')}} on-click={() => selectNewMode('cloneDefaultLayoutNew')}>
                                    <img src="assets/img/cloneDefaultLayoutNew.png"></img>
                                    <div class="title">克隆默认布局新建</div>
                                    <div class="description">以当前视图默认布局为蓝本，建立用户自定义布局面板</div>
                                </div>
                                <div class={{'tips-item': true, 'selected': Object.is(select, 'useExistingLayout')}} on-click={() => selectNewMode('useExistingLayout')}>
                                    <img src="assets/img/useExistingLayout.png"></img>
                                    <div class="title">选用已有布局</div>
                                    <div class="description">选择已经建立的自定义布局面板数据</div>
                                </div>
                            </div>
                        </div>
                        <div class="tips-action">
                            <a-button on-click={() => onCancel()}>取消</a-button>
                            <a-button type="primary" on-click={() => nextStep()} disabled={!select}>下一步</a-button>
                        </div>
                    </div>
                )
            },
            onOk: () => {
                const panelCtrl: any = (this.ctrl.ctx as any)?.panelCtrl || this.ctrl;
                if (panelCtrl.evt) {
                    if (Object.is(select, 'cloneDefaultLayoutNew')) {
                        panelCtrl.evt.emit('cloneDefaultLayout');
                    } else {
                        panelCtrl.evt.emit('itemClick', { tag: 'switchpanel' });
                    }
                }
            },
            onCancel: () => {

            }
        });
        const selectNewMode = (model: string) => {
            select = model;
            modal?.update();
        }
        const onCancel = () => {
            modal?.destroy();
        }
        const nextStep = () => {
            modal?.destroy();
            const panelCtrl: any = (this.ctrl.ctx as any)?.panelCtrl || this.ctrl;
            if (panelCtrl.evt) {
                if (Object.is(select, 'cloneDefaultLayoutNew')) {
                    panelCtrl.evt.emit('cloneDefaultLayout');
                } else if (Object.is(select, 'useExistingLayout')) {
                    panelCtrl.evt.emit('itemClick', { tag: 'switchpanel' });
                }
            }
        }
    }

    /**
     * 拖拽数据变更
     *
     * @param {*} evt
     * @memberof DesignItemBase
     */
    change(evt: any, list: any[] = []): void {
        if ((evt?.added || evt?.moved) && (this.ctrl as any)?.isDefaultLayout) {
            this.userOperationTips(evt);
        } else if (evt?.added) {
            if ((this.ctrl as any)?.isDefaultLayout) {
                this.userOperationTips(evt);
            } else {
                const data = {
                    ...evt.added,
                    element: clone(Object.assign(evt.added.element) || {}),
                };
                if (data.element.isCtrls) {
                    this.addCtrlItem(data, list);
                } else {
                    this.add(data);
                }
            }
        } else if (evt?.moved) {
            this.move(evt.moved);
        }
    }

    /**
     * 新增项
     *
     * @param {{ element: any; newIndex: number }} _opt
     * @return {*}  {Promise<void>}
     * @memberof DesignItemBase
     */
    async add(_opt: { element: any; newIndex: number }): Promise<void> {}

    /**
     * @description 新增拖拽部件
     * @param {*} arg
     * @memberof DesignItemBase
     */
    addCtrlItem(data: any, list: any[]) {
        const param = {
            psctrltypeid: data?.element?.predefinedtype,
        };
        if ((this.ctrl as any).evt) {
            (this.ctrl as any).evt.emit('itemClick', {
                tag: 'viewctrlcreate',
                param: param,
                callback: (_data: any) => {
                    if (_data.codename) {
                        Object.assign(data.element, { pssysviewpanelitemname: _data.codename, isCtrls: false });
                        this.add(data);
                    }
                },
            });
        }
    }

    /**
     * 子项移动
     *
     * @param {{ data: any; newIndex: number; oldIndex: number }} opt
     * @return {*}  {Promise<void>}
     * @memberof DesignItemBase
     */
    async move(opt: { data: any; newIndex: number; oldIndex: number }): Promise<void> {
        const { newIndex, oldIndex } = opt;
        // 根据变更位置更新排序值
        if (newIndex > oldIndex) {
            await this.updateOrderValue(oldIndex);
        } else {
            await this.updateOrderValue(newIndex);
        }
    }

    /**
     * 根据当前列表，更新排序值
     *
     * @param {number} [num=0] 更新起始下标，默认从0开始
     * @return {*}  {Promise<void>}
     * @memberof DesignItemBase
     */
    async updateOrderValue(num: number = 0): Promise<void> {
        this.disableAcc();
        for (let i = num; i < this.list.length; i++) {
            const item = this.list[i];
            item.ordervalue = generateOrderValue(i);
            item.srfordervalue = item.ordervalue;
            await this.service.UpdateTemp(this.ctx.context, item);
        }
        this.enableAcc();
    }

    /**
     * 获取拖拽容器样式
     *
     * @return {*}  {*}
     * @memberof DesignItemBase
     */
    getDraggableClass(): any {
        return {
            'transition-group': true,
            'draggable-warp': true,
            'ant-row': true,
        };
    }

    /**
     * 拖拽容器render额外参数
     *
     * @return {*}  {VNodeData}
     * @memberof DesignItemBase
     */
    getDraggableOtherParams(): VNodeData {
        return {};
    }

    /**
     * 绘制拖拽区
     *
     * @param {any[]} list
     * @param {*} content
     * @returns {*}
     * @memberof DragDesignBase
     */
    renderDraggable(list: any[], content?: any): any {
        const h = this.$createElement;
        return h(
            'draggable',
            {
                attrs: {
                    handle: this.options.handle,
                    group: this.options.group,
                    animation: this.options.animation,
                    list: list,
                    disabled: (this.ctx.ctrl as any)?.isViewDesign
                },
                class: 'draggable-container',
                on: {
                    change: (e: any) => this.change(e),
                },
            },
            [
                h(
                    'transition-group',
                    {
                        attrs: {
                            type: 'transition',
                            name: 'flip-list',
                        },
                        class: this.getDraggableClass(),
                        ...this.getDraggableOtherParams(),
                    },
                    content,
                ),
            ],
        );
    }
}
