/**
 * 针对含有组合条件的报表使用的过滤器
 */
import React from 'react'
import PropTypes from 'prop-types'
import { Modal, Form, Row, Col, Input, Icon, Button, Cascader, Select, InputNumber, DatePicker, Spin, Tag,
    // Divider
} from 'antd'
import OPERATORS from './filterOperators.js'
import './filterBox.less'
import * as service from '../../../services/index'
import URLS from '../../../constants/url'
import moment from 'moment'
const FormItem = Form.Item
const SelectOption = Select.Option
const { RangePicker } = DatePicker

let uuid = Math.ceil(Math.random() * 1000);
class FilterBox extends React.Component {
    
    constructor(props) {
        uuid = Math.ceil(Math.random() * 1000);
        super(props);
        this.state = {
            dataSources: props.dataSources || [],
            relationColumns: props.relationColumns || [],
            filterData: props.filterData || [],
            fetching: false, // 请求列数据状态
            fieldOptions: props.dataSources.map(d => {
                return {
                    name: d.code,
                    label: d.name,
                    isLeaf: false,
                }
            }).concat(props.relationColumns.length > 0 ? [{
                name: 'cus',
                label: '关联字段',
                combined: true,
                isLeaf: false,
                columns: props.relationColumns.map(r => ({
                    name: r.code,
                    type: r.relations[0].column.type,
                    label: r.name,
                    relations: r.relations
                }))
            }] : []), // 列选项
        }
    }

    static propTypes = {
        relationColumns: PropTypes.array,
        filterData: PropTypes.array
    }

    componentDidMount() {
        this.loadColumnDatas();
        const { filterData } = this.state;
        // 将原本的过滤条件生成可视化组件
        this.addFilter(filterData.map(f => {
            return {
                ...f,
                key: uuid++,
                name: f.name,
                label: f.label,
                type: f.type,
                operator: f.operator,
                operatorLabel: f.operatorLabel,
                value1: f.value1,
                value2: f.value2,
                using: f.using
            }
        }));
    }

    removeFilter = (key) => {
        const { form } = this.props;
        const filters = form.getFieldValue('filters');
        form.setFieldsValue({
            filters: filters.filter(filter => filter.key !== key),
        });
    }

    removeAllFilters = () => {
        const { form } = this.props;
        form.setFieldsValue({
            filters: [],
        });
    }

    addFilter = (filtes) => {
        const { form } = this.props;
        const filters = form.getFieldValue('filters');
        const nextFilters = filters.concat(filtes || {
            key: uuid++,
            using: true
        });
        form.setFieldsValue({
            filters: nextFilters,
        });
    }

    /**
     * 改变过滤条件字段
     */
    changeFilterName = (filter, value) => {
        const { form } = this.props;
        const filters = form.getFieldValue('filters');

        let obj = {};
        obj['columnData-' + value[1].name] = [];
        this.setState(obj);
        form.setFieldsValue({
            filters: filters.map((f) => {
                if (f.key === filter.key) {
                    f.key = uuid++; // 每次重设key值以保证界面重现渲染，解决Select数据残留的问题
                    f.name = value[1].name;
                    f.combined = value[0].name === 'cus';
                    f.dataSource = value[1].relations ? value[1].relations : { code: value[0].name, label: value[0].label };
                    f.label = value[1].label;
                    f.type = value[1].type;
                    f.operator = OPERATORS[f.type][0].value;
                    f.operatorLabel = OPERATORS[f.type][0].label;
                    f.value1 = f.value2 = (f.type === 'time' ? moment() : undefined);
                }
                return f;
            })
        });
    }

    /**
     * 改变过滤条件连接符
     */
    changeFilterOperator = (filter, value) => {
        const { form } = this.props;
        const filters = form.getFieldValue('filters');
        form.setFieldsValue({
            filters: filters.map((f) => {
                if (f.key === filter.key) {
                    // f.key = uuid++;
                    f.operator = value.key;
                    f.operatorLabel = value.label;
                    f.value1 = f.value2 = (f.type === 'time' ? moment() : undefined);
                }
                return f;
            })
        });
    }

    /** 
     * 改变过滤条件的值
     */
    changeFilterValue = (filter, value, index) => {
        const { form } = this.props;
        const filters = form.getFieldValue('filters');

        form.setFieldsValue({
            filters: filters.map((f) => {
                if (f.key === filter.key) {
                    // f.key = uuid++;
                    f[`value${index}`] = value;
                }
                return f;
            })
        });
    }

    /** 
     * 改变过滤条件的值（一次改两个）
     */
    changeFilterValues = (filter, values) => {
        const { form } = this.props;
        const filters = form.getFieldValue('filters');

        form.setFieldsValue({
            filters: filters.map((f) => {
                if (f.key === filter.key) {
                    // f.key = uuid++;
                    f[`value1`] = values[0];
                    f[`value2`] = values[1];
                }
                return f;
            })
        });
    }

    /**
     * 获得设定的过滤条件规则
     */
    getFilters = () => {
        const { form, createFilters, hideFilterBox } = this.props;
        form.validateFields((err, values) => {
            if(!err) {
                let filters = values.filters.map(f => ({
                    ...f,
                    filterLabel: this.createFilterLabel(f)
                }));
                createFilters && createFilters(filters);
                hideFilterBox();
            }
        })
    }

    fetchColumnData = (filter, options) => {
        const { keyword, mandatory } = options || {};
        const { combined, dataSource } = filter;
        let columnData = this.state['columnData-' + filter.name]
        if(!columnData || columnData.length === 0 || mandatory) {
            let obj = {fetching: true};
            obj['columnData-' + filter.name] = []
            this.setState(obj, () => {
                const body = combined ? dataSource.map(d => ({
                    id: d.dataSource.code,
                    columnName: d.column.name,
                    keyword,
                })) : {
                    id: dataSource.code,
                    columnName: filter.name,
                    keyword, 
                };
                service.fetch({
                    url: combined ? URLS.DATASOURCE_QUERY_COLUMNDATA_MUL : URLS.DATASOURCE_QUERY_COLUMNDATA,
                    allow: true,
                    body: body,
                }).then(r => {
                    if(r.code > 0) {
                        return r;
                    }else {
                        let obj = {};
                        throw obj;
                    }
                }).then(r => {
                    const resData = r.data || [];
                    let obj = {fetching: false};
                    obj['columnData-' + filter.name] = resData.map(d => d || 'null')
                    this.setState(obj);
                }).catch(ex => {
                    let obj = {fetching: false};
                    obj['columnData-' + filter.name] = [];
                    this.setState(obj);
                    console.error('fetch error', ex);
                });
            });
        }
    }

    /**
     * 生成过滤规则文本
     */
    createFilterLabel = (filter) => {
        let { label, operator, operatorLabel, type, value1, value2 } = filter;
        let filterLabel;

        if(type === 'string' || type === 'index') {
            if(operator === 'null' || operator === 'notNull') {
                filterLabel = `${label} ${operatorLabel}`;
            }else {
                filterLabel = `${label} ${operatorLabel} ${value1}`;
            }
        }else if(type === 'scale') {
            if(operator === 'null' || operator === 'notNull') {
                filterLabel = `${label} ${operatorLabel}`;
            }else if(operator === 'between') {
                filterLabel = `${label} ${operatorLabel} ${value1} ~ ${value2}`; 
            }else {
                filterLabel = `${label} ${operatorLabel} ${value1}`; 
            }
        }else if(type === 'time') {
            value1 = moment(value1).format('YYYY/MM/DD');
            value2 = moment(value2).format('YYYY/MM/DD');
            if(operator === 'null' || operator === 'notNull') {
                filterLabel = `${label} ${operatorLabel}`;
            }else if(operator === 'between') {
                filterLabel = `${label} ${operatorLabel} ${value1} ~ ${value2}`;
            }else {
                filterLabel = `${label} ${operatorLabel} ${value1}`;
            }
        }else if(type === 'categorical') {
            if(operator === 'null' || operator === 'notNull') {
                filterLabel = `${label} ${operatorLabel}`;
            }else {
                filterLabel = `${label} ${operatorLabel} ${value1}`;
            }
        }else {
            filterLabel = '错误条件';
        }
        return filterLabel;
    }

    getFilterItems() {
        const { getFieldDecorator, getFieldValue } = this.props.form;
        getFieldDecorator('filters', { initialValue: [] });
        const filters = getFieldValue('filters');

        const filterItems = filters.map((f, index) => {
            let { key, name, type, dataSource, operator } = f;
            return (
                <Row key={`filterDiv[${key}]`}>
                    <Col span={22}>
                        <Col span={7}>
                            <FormItem key={key}>
                                {getFieldDecorator(`filterName${key}`, {
                                    initialValue: dataSource ? (dataSource instanceof Array ? ['cus', name] : [dataSource.code, name]) : undefined,
                                    rules: [{ required: true, message: '列名不能为空' }]
                                })(
                                    this.generateFieldItem(f)
                                )}
                            </FormItem>
                        </Col>
                        <Col span={5}>
                            <FormItem key={key} className='filterOperator'>
                                {getFieldDecorator(`filterOperator${key}`, {
                                    initialValue: operator?{key: operator}:undefined,
                                    rules: [{ required: true, message: '操作类型不能为空' }]
                                })(
                                    this.generateOperatorItem(f)
                                )}
                            </FormItem>
                        </Col>
                        <Col span={(operator&&operator!=='null'&&operator!=='notNull')?(operator==='between'?(type === 'time' ? 12: 6):12):0}>
                            <FormItem
                                key={key}
                                className='filterValueOne'
                            >
                                {this.generateValueItem(f, 1, index)}
                            </FormItem>
                        </Col>
                        {operator==='between' && type !== 'time' && <Col span={6}>
                            <FormItem
                                key={key}
                                className='filterValueTwo'
                            >
                                {this.generateValueItem(f, 2, index)}
                            </FormItem>
                        </Col>}
                    </Col>
                    <Col span={2} className='filter-remove-col' >
                        <Icon
                            className="dynamic-delete-button"
                            type="minus-circle"
                            onClick={() => { this.removeFilter(key) }}
                        />
                    </Col>
                </Row>
            );
        });

        return filterItems;
    }

    generateFieldItem(f) {
        const { fieldOptions } = this.state;

        return <Cascader
            allowClear={false}
            fieldNames={{ label: 'label', value: 'name', children: 'columns' }}
            options={fieldOptions}
            loadData={this.loadColumnData}
            placeholder=''
            displayRender={label=>label[1]}
            onChange={(value, selectedOptions) => {
                this.changeFilterName(f, selectedOptions)
            }}
        />
    }

    generateOperatorItem(f) {
        return (<Select
            labelInValue={true}
            onChange={(value) => {this.changeFilterOperator(f, value)}}
            dropdownMatchSelectWidth={false}
        >
            {OPERATORS[f.type].map((o, i) => {
                return <SelectOption key={i} value={o.value}>{o.label}</SelectOption>;
            })}
        </Select>)
    }

    generateTimeTags = (filter, index, defaultValue, filterIndex) => {
        const timeTypes = [
            { dynamic: true, label: '今天', name: 'today' },
            { dynamic: true, label: '本月', name: 'month' },
            { dynamic: true, label: '上月', name: 'lastmonth' },
            { dynamic: true, label: '近半年', name: 'halfyear' },
            { dynamic: true, label: '本年', name: 'year' },
            { dynamic: true, label: '上年', name: 'lastyear' },
        ]
        return timeTypes.map(t => <Tag key={t.name} className={`cus-time-tag${defaultValue && defaultValue.name === t.name ? ' current' : ''}`} onClick={() => {
            this.changeFilterValue(filter, t, index);
            let obj = {};
            obj[`datePickerOpen-${filterIndex}-${index}`] = false;
            this.setState(obj);
        }}>{t.label}</Tag>);
    }

    generateValueItem = (filter, index, filterIndex) => {
        const { fetching } = this.state;
        // const dropdownOpen = filter.key ? (this.state['dropdownOpen-' + filter.key] || false) : false;
        const columnData = filter.name ? (this.state['columnData-' + filter.name] || []) : [];
        let field;
        const { type, operator } = filter;

        let defaultValue = type==='time' ? (
            operator === 'between' ? (
                filter['value1'] ? [moment(filter['value1']), moment(filter['value2'])] : null
            ) :
            (filter['value' + index] ? ( filter['value' + index].dynamic ? ( filter['value' + index] ) : moment(filter['value' + index]) ) : null)
        ) : filter['value' + index]
        const commonProps = { placeholder: '无默认值', defaultValue }

        if(['index', 'string'].indexOf(type) !== -1) {
            field = <Input { ...commonProps } onBlur={(e) => {this.changeFilterValue(filter, e.target.value, index)}}/>
        }else if(['scale', 'ordinal'].indexOf(type) !== -1) {
            field = <InputNumber { ...commonProps } onBlur={(e) => {this.changeFilterValue(filter, e.target.value, index)}}/>
        }else if(type === 'time') {
            if(operator === 'between') {
                field = <RangePicker
                    key={Math.random()}
                    defaultValue={defaultValue}
                    ranges={{
                        '今天': [moment().startOf('day'), moment().endOf('day')],
                        '本月': [moment().startOf('month'), moment().endOf('month')],
                        '上月': [moment().month(moment().month() - 1).startOf('month'), moment().month(moment().month() - 1).endOf('month')],
                        '近半年': [moment().subtract(6, "months").startOf('day'), moment().endOf('day')],
                        '本年': [moment().startOf('year'), moment().endOf('year')],
                        '上年': [moment().subtract(1, "years").startOf('year'), moment().subtract(1, "years").endOf('year')],
                    }}
                    showTime={false}
                    format="YYYY-MM-DD"
                    onChange={values => {
                        this.changeFilterValues(filter, [values[0], values[1]]);
                    }}
                >
                </RangePicker>
            }else {
                field = <div className='cus-time-picker' >
                    <Input
                        key={Math.random()}
                        allowClear
                        // suffix={<Icon style={{ color: 'rgba(0, 0, 0, 0.25)' }} type="calendar" />}
                        defaultValue={ commonProps.defaultValue ? (commonProps.defaultValue.dynamic ? commonProps.defaultValue.label : moment(commonProps.defaultValue).format('YYYY-MM-DD')) : '' }
                        onFocus={(e) => {
                            let obj = {};
                            let inputBox = e.target.getBoundingClientRect();
                            const warpHeight = 379;
                            let bottomY = inputBox.top + inputBox.height + warpHeight + 10;
                            let overH = bottomY - document.body.offsetHeight
                            obj[`datePickerOpen-${filterIndex}-${index}`] = true;
                            obj[`datePicker-${filterIndex}-${index}-marginTop`] = overH > 0 ? `-${overH}px` : 0;
                            this.setState(obj);
                        }}
                        onChange={() => {
                            // 因为onFocus方法弹出了浮层，onChange方法只在点击清楚图标时会调用（相当于不可编辑的input），所以这里只做清除
                            this.changeFilterValue(filter, null, index)
                        }}
                    />
                    <DatePicker
                        key={Math.random()}
                        style={{ marginTop: this.state[`datePicker-${filterIndex}-${index}-marginTop`] }}
                        defaultValue={commonProps.defaultValue ? (commonProps.defaultValue.dynamic ? null : commonProps.defaultValue) : null}
                        showToday={operator !== '='}
                        open={this.state[`datePickerOpen-${filterIndex}-${index}`]}
                        onOpenChange={status => {
                            let obj = {};
                            obj[`datePickerOpen-${filterIndex}-${index}`] = status;
                            this.setState(obj);
                        }}
                        onChange={(value) => {this.changeFilterValue(filter, value, index)}}
                        renderExtraFooter={operator === '=' ? () => this.generateTimeTags(filter, index, commonProps.defaultValue, filterIndex) : null}
                    />
                </div>
            }
        }else if(type === 'categorical') { // 类别
            if(operator === 'include' || operator==='notInclude') { // 包含/不包含
                field = <Input { ...commonProps } onBlur={(e) => {this.changeFilterValue(filter, e.target.value, index)}}/>
            }else if(operator === 'contain' || operator === 'notContain') { // 包括/不包括
                field = (<Select 
                    { ...commonProps }
                    allowClear
                    mode='multiple'
                    showSearch
                    // open={dropdownOpen}
                    // onDropdownVisibleChange={(open) => {
                    //     this.onDropdownVisibleChange(filter, open);
                    // }}
                    dropdownMatchSelectWidth={false}
                    notFoundContent={fetching ? <Spin size="small" /> : '无'}
                    onSearch={(value) => {this.fetchColumnData(filter, { keyword: value, mandatory: true })}}
                    onFocus={() => {this.fetchColumnData(filter)}}
                    onChange={(value) => {this.changeFilterValue(filter, value, index)}}
                    // dropdownRender={menu => (
                    //     <div>
                    //         {menu}
                    //         {columnData.length > 0 && <Divider style={{ margin: '4px 0' }} />}
                    //         {columnData.length > 0 && <div style={{ padding: '8px', cursor: 'pointer' }}>
                    //             {/** https://github.com/ant-design/ant-design/issues/13448 */}
                    //             <span onMouseDown={this.lockClose} onMouseUp={this.lockClose} onClick={() => {
                    //                 if(commonProps.defaultValue && commonProps.defaultValue.length === columnData.length) {
                    //                     this.changeFilterValue(filter, [], index)
                    //                 }else {
                    //                     this.changeFilterValue(filter, columnData, index)
                    //                 }
                    //                 let obj = {};
                    //                 obj['dropdownOpen-' + filter.key] = false;
                    //                 this.setState(obj);
                    //             }}>    
                    //                 <Icon type={ commonProps.defaultValue && commonProps.defaultValue.length === columnData.length ? 'check-square' : 'border' } /> { commonProps.defaultValue && commonProps.defaultValue.length === columnData.length ? '取消全选' : '全选' }
                    //             </span>
                    //         </div>}
                    //     </div>
                    // )}
                >
                    { columnData.map((s, i) => {
                        return <SelectOption key={i} value={s}>{s}</SelectOption>
                    }) }
                </Select>)
            }else { // 等于/不等于
                field = (<Select
                    { ...commonProps }
                    allowClear
                    mode='single'
                    showSearch
                    dropdownMatchSelectWidth={false}
                    notFoundContent={fetching ? <Spin size="small" /> : '无'}
                    onSearch={(value) => {this.fetchColumnData(filter, { keyword: value, mandatory: true })}}
                    onFocus={() => {this.fetchColumnData(filter)}}
                    onChange={(value) => {this.changeFilterValue(filter, value, index)}}
                >
                    { columnData.map((s, i) => {
                        return <SelectOption key={i} value={s}>{s}</SelectOption>
                    }) }
                </Select>)
            }
        }else {
            field = <Input { ...commonProps } onBlur={(e) => {this.changeFilterValue(filter, e.target.value, index)}}/> 
        }

        return field;
    }

    lockClose = e => {
        clearTimeout(this.lock);
        this.lock = setTimeout(() => {
          this.lock = null;
        }, 100);
    };

    // onDropdownVisibleChange = (filter, open) => {
    //     if (this.lock) return;
    //     let obj = {};
    //     obj['dropdownOpen-' + filter.key] = open;
    //     this.setState(obj);
    // };

    loadColumnDatas() {
        let { fieldOptions } = this.state;
        fieldOptions.forEach(f => {
            if(!f.combined) {
                this.loadColumnData([f]);
            }
        });
    }

    loadColumnData = (selectedOptions) => {
        let { fieldOptions } = this.state;
        const targetOption = selectedOptions[selectedOptions.length - 1];
        const stateIdx = fieldOptions.findIndex(f => f.name === targetOption.name);
        targetOption.loading = true;
    
        service.fetch({
            url: URLS.DATASOURCE_QUERY_DATACOLUMNS,
            allow: true,
            body: targetOption.name
        }).then(r => {
            targetOption.loading = false;
            if(r.code > 0) {
                return r;
            }else {
                let obj = {};
                throw obj;
            }
        }).then(r => {
            const resData = r.data || [];
            let columns = resData.map((c, i) => {
                return {
                    key: i,
                    name: c.columnName,
                    label: c.columnRaname,
                    type: c.columnType,
                    groupable: c.isGroup==='1'?true:false,
                    filterable: c.isFilter==='1'?true:false
                }
            }).filter(c => c.filterable);
            fieldOptions[stateIdx].columns = columns;
            this.setState({
                fieldOptions: fieldOptions
            });
        }).catch(ex => {
            console.error('fetch error', ex);
        })
    }

    render() {
        const { visibleFilterBox, hideFilterBox } = this.props;

        return (
            <Modal
                className='filter-box'
                title='筛选条件'
                visible={visibleFilterBox}
                footer={<div>
                    <Button onClick={this.removeAllFilters}>清空条件</Button>
                    <Button onClick={hideFilterBox}>取消</Button>
                    <Button type='primary' onClick={this.getFilters}>确定</Button>
                    </div>
                }
                onOk={this.getFilters}
                onCancel={hideFilterBox}
                maskClosable={false}
                destroyOnClose={true}
            >
                <Form size='small'>
                    {this.getFilterItems()}
                    <Row>
                        <Col>
                            <FormItem>
                                <Button
                                    className='filter-add-button'
                                    type="dashed"
                                    onClick={() => {this.addFilter()}}
                                >
                                    <Icon type="plus" />
                                    添加
                                </Button>
                            </FormItem>
                        </Col>
                    </Row>
                </Form>
            </Modal>
        );
    }
}

export default Form.create()(FilterBox);