import React from 'react';
import { Row, Col, Button, Input, Select, DatePicker, DateRangePicker, AutoComplete } from 'neatui';
import xhr from 'SERVICE/xhr';
import './index.scss';
import BaseComponent from 'COMPONENT/common/BaseComponent';
import FieldLayout from 'COMPONENT/container/FieldLayout';
import { error } from 'UTIL/notification';
import { isArray, parseData2Url, getSearchParams, parseFixedParameter } from 'UTIL/util';
import moment from 'moment';
import 'moment/locale/zh-cn';
import projectConfig from 'CONFIG/projectConfig.json';

moment.locale('zh-cn');

const localHost = projectConfig.localhost || [];
localHost.push('localhost');

class SearchBar extends BaseComponent {
    constructor(props, context) {
        super(props, context);
        const { getInstance } = props;
        if (typeof getInstance === 'function') {
            getInstance(this);
        }
        const searchParams = getSearchParams();
        this.env = localHost.indexOf(window.location.hostname) > -1 ? 'local.' : '';
        this.state = {
            suggest: {},
            senior: false
        };
        const searchForm = {};
        const filterMap = {};
        this.searchForm = {};
        this.refslef = {};
        this.filter = this.props.filter || [];
        this.senior = [];
        this.notSenior = [];
        this.formatInfo = {};
        this.notReset = [];
        this.hasSenior = false;
        this.mustArr = [];
        for (let i = 0; i < this.filter.length; i+=1) {
            const item = this.filter[i];
            filterMap[item.key] = item;
            if (item.isMust) this.mustArr.push(item);
            if (item.type === 'daterangepicker') {
                const isArr = isArray(item.defaultValue) && item.defaultValue.length > 1;
                // for state
                searchForm[item.startDate] = isArr ? moment().subtract(item.defaultValue[0], 'days') : '';
                // for reset
                this.searchForm[item.startDate] = isArr ? moment().subtract(item.defaultValue[0], 'days') : '';
                searchForm[item.endDate] = isArr ? moment().subtract(item.defaultValue[1], 'days') : '';
                this.searchForm[item.endDate] = isArr ? moment().subtract(item.defaultValue[1], 'days') : '';
                // for props search
                const defaultStartDate = isArr ? moment().subtract(item.defaultValue[0], 'days').format(item.format || 'YYYY-MM-DD') : '';
                const defaultEndDate = isArr ? moment().subtract(item.defaultValue[1], 'days').format(item.format || 'YYYY-MM-DD') : '';
                this.props.searchFormData[item.startDate] = isArr && item.ajaxType === 'timestamp' ? moment(defaultStartDate).valueOf() : defaultStartDate;
                this.props.searchFormData[item.endDate] = isArr && item.ajaxType === 'timestamp' ? (moment(defaultEndDate).valueOf() + parseInt(item.endplus || 0, 10)) : defaultEndDate;
                if (item.format) {
                    this.formatInfo[item.startDate] = {format: item.format, ajaxType: item.ajaxType};
                    this.formatInfo[item.endDate] = {format: item.format, ajaxType: item.ajaxType};
                }
                if (item.notReset) {
                    this.notReset.push(item.startDate);
                    this.notReset.push(item.endDate);
                }
            } else if (item.type === 'datepicker') {
                const defaultDate = item.defaultValue ? moment().subtract(item.defaultValue, 'days') : '';
                searchForm[item.key] = defaultDate;
                this.searchForm[item.key] = defaultDate;
                this.props.searchFormData[item.key] = defaultDate ? defaultDate.format(item.format || 'YYYY-MM-DD') : '';
                this.props.searchFormData[item.key] = defaultDate && item.ajaxType === 'timestamp' ? moment(defaultDate.format(item.format)).valueOf() : this.props.searchFormData[item.key];
                if (item.notReset) {
                    this.notReset.push(item.key);
                }
            } else {
                searchForm[item.key] = item.defaultValue;
                this.searchForm[item.key] = item.defaultValue;
                this.state[item.key] = [];
                if (item.senior) {
                    this.hasSenior = true;
                    this.senior.push(item.key);
                } else {
                    this.notSenior.push(item.key);
                    this.props.searchFormData[item.key] = searchParams[item.key] || item.defaultValue;
                }
                if (item.notReset) this.notReset.push(item.key);
            }
        }
        this.state.searchForm = {
            ...searchForm,
            ...searchParams
        };
        this.state.filterMap = {
                ...filterMap
            };
        if (this.props.updateSearchBar) this.props.updateSearchBar();
    }

    componentDidMount() {
        for (let i = 0; i < this.filter.length; i+=1) {
            const item = this.filter[i];
            if (!item[[`${this.env}url`]] && !item[[`${this.env}nextUrl`]]) continue;
            if (!item.notInit) this.getSearchFormListHandler(item);
            if (item.nextKey) {
                this.getSonData(item.defaultValue, item);
            }
        }
    }

    searchHandler = () => {
        if (!this.state.senior) {
            Object.keys(this.searchForm).forEach((key) => {
                if (this.senior.indexOf(key) > -1) {
                    delete this.props.searchFormData[key];
                }
            })
        } else {
            Object.keys(this.searchForm).forEach((key) => {
                this.props.searchFormData[key] = this.props.searchFormData[key] !== '' ?  this.props.searchFormData[key] : (this.searchForm[key] || '');
            })
        }
        let canSearch = true;
        this.mustArr.forEach(item => {
            if (this.props.searchFormData[item.key] === '' || this.props.searchFormData[item.key] === undefined) {
                canSearch = false;
                error(`${item.label}为必填项!`);
            }
        });
        if (canSearch) this.props.search();
    };

    resetConditionHandler = () => {
        const mine = this;
        const { filterMap } = mine.state;
        const resetForm = {};
        Object.keys(mine.searchForm).forEach((key) => {
            if (this.notReset.indexOf(key) > -1) {
                resetForm[key] = mine.state.searchForm[key];
                if (mine.formatInfo[key] && mine.formatInfo[key].format) {
                    mine.props.searchFormData[key] = mine.state.searchForm[key].format ? mine.state.searchForm[key].format(mine.formatInfo[key].format) : mine.state.searchForm[key];
                    if (mine.formatInfo[key].ajaxType === 'timestamp') {
                        mine.props.searchFormData[key] = moment(mine.state.searchForm[key].format(mine.formatInfo[key].format)).valueOf();
                    }
                } else {
                    mine.props.searchFormData[key] = mine.state.searchForm[key];
                }
            } else {
                resetForm[key] = mine.searchForm[key];
                if (mine.formatInfo[key] && mine.formatInfo[key].format) {
                    mine.props.searchFormData[key] = mine.searchForm[key].format ? mine.searchForm[key].format(mine.formatInfo[key].format) : mine.searchForm[key];
                    if (mine.formatInfo[key].ajaxType === 'timestamp') {
                        mine.props.searchFormData[key] = moment(mine.searchForm[key].format(mine.formatInfo[key].format)).valueOf();
                    }
                } else {
                    mine.props.searchFormData[key] = mine.searchForm[key];
                }
                mine.getSearchFormListHandler(filterMap[key]);
            }
        });
        mine.setState({
            searchForm: resetForm
        }, () => {
            if (mine.props.justReset) this.props.resetHandler();
            else mine.searchHandler();
        });
    };

    switchSenior = () => {
        const { senior } = this.state;
        Object.keys(this.searchForm).forEach((key) => {
            if (this.senior.indexOf(key) > -1)
                this.props.searchFormData[key] = this.searchForm[key];
        });
        this.setState({
            searchForm: {...this.searchForm, ...this.props.searchFormData},
            senior: !senior
        });
    };

    onSearchInputChange = (vals, val, name) => {
        this.props.searchFormData[name] = vals;
        const { searchForm } = this.state;
        const willUpdateData = {
            searchForm: {
                ...searchForm,
                [name]: vals
            }
        };
        this.setState(willUpdateData);
    };

    resetDefaultValue = (config, willUpdateData) => {
        const { filterMap } = this.state;
        const { searchForm } = willUpdateData;
        this.props.searchFormData[config.nextKey] = this.searchForm[config.nextKey] !== undefined && this.searchForm[config.nextKey] !== null ? this.searchForm[config.nextKey] : '';
        searchForm[config.nextKey] = this.searchForm[config.nextKey] !== undefined && this.searchForm[config.nextKey] !== null ? this.searchForm[config.nextKey] : '';
        if(filterMap[config.nextKey].nextKey) {
            this.resetDefaultValue(filterMap[config.nextKey], willUpdateData);
        }
    }

    resetDefaultDataMap = (vals, config) => {
        const { filterMap } = this.state;
        this.getSonData(vals, config);
        if(filterMap[config.nextKey].nextKey) {
            this.resetDefaultDataMap(filterMap[config.nextKey].defaultValue, filterMap[config.nextKey]);
        }
    }

    onSearchChange = (vals, val, name, config) => {
        const mine = this;
        this.props.searchFormData[name] = vals;
        const { searchForm } = this.state;
        const willUpdateData = {
            searchForm: {
                ...searchForm,
                [name]: vals
            }
        };
        if (config.nextKey) {
            mine.resetDefaultValue(config, willUpdateData);
        }
        this.setState(willUpdateData, () => {
            if (config.autoTrigger === undefined && projectConfig.autoTrigger) mine.searchHandler();
            else if (config.autoTrigger) mine.searchHandler();
            if (config.nextKey) {
                this.resetDefaultDataMap(vals, config);
            }

            if (config.control && isArray(config.control)) {
                for (let i = 0; i < this.filter.length; i+=1) {
                    const item = this.filter[i];
                    const postData = {};
                    postData[name] = val;
                    if (config.control.indexOf(item.key) > -1 && item[`${this.env}url`]) {
                        this.getSearchFormListHandler(item, postData);
                    }
                }
            }

            this.getSonData(vals, config);
        });
    };

    onSearchHandler = (val, config) => {
        const postData = {};
        postData[config.ajaxKey] = val;
        this.getSearchFormListHandler(config, postData);
    };

    onDateChange = (time, config) => {
        const date = time ? time.format(config.format || 'YYYY-MM-DD') : '';
        this.props.searchFormData[config.key] = date;
        const { searchForm } = this.state;
        this.setState({
            searchForm: {
                ...searchForm,
                [config.key]: date
            }
        });
    };

    onDateRangeChange = (time, config) => {
        const startDate = time[0] ? time[0].format(config.format || 'YYYY-MM-DD') : '';
        const endDate = time[1] ? time[1].format(config.format || 'YYYY-MM-DD') : '';
        if (startDate)
            this.props.searchFormData[config.startDate] = config.ajaxType === 'timestamp' ? moment(startDate).valueOf() : startDate;
        else
            this.props.searchFormData[config.startDate] = '';
        if (startDate)
            this.props.searchFormData[config.endDate] = config.ajaxType === 'timestamp' ? (moment(endDate).valueOf() + parseInt(config.endplus || 0, 10)) : endDate;
        else
            this.props.searchFormData[config.endDate] = '';
        const configTime = {};
        configTime[config.startDate] = startDate;
        configTime[config.endDate] = endDate;
        const { searchForm } = this.state;
        this.setState({
            searchForm: {
                ...searchForm,
                ...configTime
            }
        });
    };

    getSearchFormListHandler = (item, postData) => {
        const mine = this;
        const { suggest } = mine.state;
        const locationSearch = {};
        if (item.isNeedLocationSearch && isArray(item.isNeedLocationSearch)) {
            for (let i = 0; i < item.isNeedLocationSearch.length; i+=1) {
                const key = item.isNeedLocationSearch[i];
                locationSearch[key] = mine.searchParams[key];
            }
        }
        const { data, url } = parseData2Url({
            ...parseFixedParameter(item.fixedParameter),
            ...locationSearch,
            ...(postData || {})
        }, item[`${this.env}url`]);
        if (url) {
            xhr({
                url,
                method: item.method || 'get',
                data,
                type: 'json',
			    contentType: item.contentType,
                notSwitchArrToStr: item.notSwitchArrToStr
            }).then((rs) => {
                if (rs[projectConfig.codeKey] === projectConfig.code) {
                    const obj = {};
                    if (item.type === 'suggest') {
                        suggest[item.key] = rs.data || [];
                    } else if (item.listStr === true) {
                        obj[item.key] = rs.data && isArray(rs.data) ? rs.data.map(dItem => { return { "id": dItem, "name": dItem } }) : []; // eslint-disable-line array-callback-return
                    } else {
                        obj[item.key] = rs.data || [];
                    }
                    mine.setState({
                        ...obj,
                        suggest
                    });
                } else {
                    error(rs[projectConfig.msg]);
                }
            });
        }
    };

    getSonData = (value, item) => {
        const mine = this;
        const postData = {};
        postData[item.nextAjaxKey] = value;
        const url = item[`${this.env}nextUrl`];
        if (url) {
            xhr({
                url,
                method: item.nextMethod || 'get',
                data: {
                    ...parseFixedParameter(item.fixedParameter),
                    ...postData
                },
                type: 'json',
                contentType: item.nextContentType,
                notSwitchArrToStr: item.nextNotSwitchArrToStr
            }).then((rs) => {
                if (rs[projectConfig.codeKey] === projectConfig.code) {
                    const obj = {};
                    obj[item.nextKey] = [];
                    if (item.nextListStr === true) {
                        obj[item.nextKey] = rs.data && isArray(rs.data) ? rs.data.map(dItem => { return { "id": dItem, "name": dItem } }) : []; // eslint-disable-line array-callback-return
                    } else {
                        obj[item.nextKey] = rs.data || [];
                    }
                    mine.setState(Object.assign({}, obj, { sonLoading: !mine.state.sonLoading}));
                } else {
                    error(rs[projectConfig.msg]);
                }
            });
        }
    }

    inputSuggest = (value = '', item) => {
        const mine = this;
        const { suggest } = mine.state;
        const url = item[`${this.env}url`];
        if (url && !item.cache) {
            const postData = {};
            postData[item.ajaxKey] = value;
            xhr({
                url,
                method: item.method || 'get',
                data: {
                    ...parseFixedParameter(mine.config.fixedParameter),
                    ...parseFixedParameter(item.fixedParameter),
                    ...postData
                },
                type: 'json',
                contentType: item.contentType,
                notSwitchArrToStr: item.notSwitchArrToStr
            }).then((rs) => {
                if (rs[projectConfig.codeKey] === projectConfig.code) {
                    suggest[item.key] = rs.data || [];
                    mine.setState({
                        suggest
                    });
                } else {
                    error(rs[projectConfig.msg]);
                }
            });
        }
    }

    keypress = (e, config) => {
        const mine = this;
        if (e.which !== 13) return;
        if (config.autoTrigger === undefined && projectConfig.autoTrigger) mine.searchHandler();
        else if (config.autoTrigger) mine.searchHandler();
    }

    createFormItem = (filter) => {
        const result = [];
        const { searchForm, suggest } = this.state;
        const { aliasArrMap } = this.props;
        const placeholderInput = '请输入';
        const placeholderSelect = '请选择';
        for (let i = 0; i < filter.length; i+=1) {
            const item = filter[i];
            const style = item.senior ? 'none' : 'inline-block';
            let btnFlag = true;
            for (let c = 0; c < (item.condition || []).length; c+=1) {
                const conditionItem = item.condition[c];
                if (conditionItem.oper === 'notcontain') {
                    btnFlag = true;
                    if (conditionItem.conValues.indexOf(searchForm[conditionItem.conKey]) > -1) {
                        btnFlag = false;
                        break;
                    }
                } else if (conditionItem.oper === 'contain') {
                    btnFlag = true;
                    if (conditionItem.conValues.indexOf(searchForm[conditionItem.conKey]) === -1) {
                        btnFlag = false;
                        break;
                    }
                }
            }
            if (!btnFlag) continue;
            if (item.type === 'input') {
                result.push(
                    <FieldLayout
                        className={`searchbar-${item.className || ''}`}
                        style={ {display: this.state.senior ? 'inline-block' : style, margin: '0 8px', ...item.style} }
                        label={<span>{item.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    >
                        <Input
                            type={item.inputType || 'text'}
                            autoComplete="off"
                            value={this.state.searchForm[item.key] || ''}
                            onChange={(e, val, name = item.key, config = item) => this.onSearchInputChange(val, val, name, config)}
                            onKeyUp={(e) => this.keypress( e, item )}
                            style={{ width: item.width || 150, margin: '8px' }}
                            placeholder={item.placeholder || (placeholderInput + item.label)}/>
                    </FieldLayout>
                );
            } else if (item.type === 'suggest') {
                result.push(
                    <FieldLayout
                        className={`searchbar-${item.className || ''}`}
                        style={ {display: this.state.senior ? 'inline-block' : style, margin: '0 8px', ...item.style} }
                        label={<span>{item.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    >
                        <AutoComplete
                            onKeyUp={(e) => this.keypress( e, item )}
                            suggestions={ suggest[item.key] || [] }
                            defaultValue={this.state.searchForm[item.key] || ''}
                            style={{ width: item.width || 150, margin: '8px' }}
                            onChange={(vals, val, name = item.key, config = item) => this.onSearchInputChange(vals, val, name, config)}
                            placeholder={item.placeholder || (placeholderInput + item.label)} />
                    </FieldLayout>
                );
            } else if (item.type === 'select') {
                const data = [].concat(item.data || []).concat(item.alias && aliasArrMap ? (aliasArrMap[item.alias] || []) : []).concat(this.state[item.key] || []);
                const selectItems = data.map(selectItem => {return { 'label': selectItem[item.dataLabel || 'name'], 'value': selectItem[item.dataKey || 'id'] }});
                result.push(
                    <FieldLayout
                        className={`searchbar-${item.className || ''}`}
                        style={ {display: this.state.senior ? 'inline-block' : style, margin: '0 8px', ...item.style} }
                        label={<span>{item.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    >
                        <Select
                            searchable
                            defaultValue={this.state.searchForm[item.key]}
                            onChange={(vals, val, name = item.key, config = item) => this.onSearchChange(vals, val, name, config)}
                            onSearch={(e, val, config = item) => {if (item.searchable) this.onSearchHandler(val, config)}}
                            needReceive={item.searchable || false}
                            style={{ width: item.width || 120, margin: '8px' }}
                            placeholder={item.placeholder || (placeholderSelect + item.label)}
                            options={item.notAll ? [...selectItems] : [{ label: '全部', value: '' }, ...selectItems]}
                        ></Select>
                    </FieldLayout>
                );
            } else if (item.type === 'multselect') {
                const data = [].concat(item.data || []).concat(item.alias && aliasArrMap ? (aliasArrMap[item.alias] || []) : []).concat(this.state[item.key] || []);
                const selectItems = data.map(selectItem => {return { 'label': selectItem[item.dataLabel || 'name'], 'value': selectItem[item.dataKey || 'id'] }});
                result.push(
                    <FieldLayout
                        className={`searchbar-${item.className || ''}`}
                        style={ {display: this.state.senior ? 'inline-block' : style, margin: '0 8px', ...item.style} }
                        label={<span>{item.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    >
                        <Select
                            searchable
                            multiple
                            defaultValue={this.state.searchForm[item.key]}
                            onChange={(vals, val, name = item.key, config = item) => this.onSearchChange(vals, val, name, config)}
                            needReceive={item.searchable || false}
                            style={{ width: item.width || 120, margin: '8px' }}
                            placeholder={item.placeholder || (placeholderSelect + item.label)}
                            options={item.notAll ? [...selectItems] : [{ label: '全部', value: '' }, ...selectItems]}
                        ></Select>
                    </FieldLayout>
                );
            } else if (item.type === 'daterangepicker') {
                let dateRangePickerProps = Object.assign({
                    format: item.format || 'YYYY-MM-DD',
                    style: { width: item.width || 400 },
                    onChange: (time, config = item) => this.onDateRangeChange(time, config),
                    clearable: item.clearable && true
                }, item.option || {});
                if (this.state.searchForm[item.startDate] && this.state.searchForm[item.endDate]) {
                    dateRangePickerProps = Object.assign(
                        dateRangePickerProps,
                        { defaultValue: [moment(this.state.searchForm[item.startDate]), moment(this.state.searchForm[item.endDate])] }
                    );
                }
                result.push(
                    <FieldLayout
                        className={`searchbar-${item.className || ''}`}
                        style={ {display: this.state.senior ? 'inline-block' : style, margin: '0 8px', ...item.style} }
                        label={<span>{item.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    >
                        <DateRangePicker {...dateRangePickerProps} />
                    </FieldLayout>
                );
            } else if (item.type === 'datepicker') {
                const datePickerProps = Object.assign({
                    format: item.format || 'YYYY-MM-DD',
                    defaultValue: this.state.searchForm[item.key] ? moment(this.state.searchForm[item.key]) : '',
                    style: { width: item.width || 200, margin: '8px' },
                    onChange: (time, config = item) => this.onDateChange(time, config),
                    clearable: item.clearable && true
                }, item.option || {});
                result.push(
                    <FieldLayout
                        className={`searchbar-${item.className || ''}`}
                        style={ {display: this.state.senior ? 'inline-block' : style, margin: '0 8px', ...item.style} }
                        label={<span>{item.isMust ? <span className="required">*</span> : ''}{item.label}</span>}
                    >
                        <DatePicker {...datePickerProps} />
                    </FieldLayout>
                );
            }
        }
        return result;
    };

    render() {
        return (
            <Row className="mb-10 component-search-bar" style={this.props.style || {}}>
                <Col>
                    <div className={!this.props.nbg ? "section" : ''}>
                        {this.createFormItem(this.filter)}
                        {
                            this.hasSenior ? <Button
                                shape="dashed"
                                onClick={this.switchSenior}
                                style={{ marginRight: '10px' }}>
                                {this.state.senior ? '普通模式' : '高级模式'}
                            </Button> : ''
                        }
                        <Button
                            variant="contained" color="primary"
                            onClick={this.searchHandler}
                            style={{ marginLeft: '10px', marginRight: '10px', verticalAlign: 'baseline' }}
                        >{this.props.filterLabel || '搜索'}</Button>
                        {
                            !this.props.noReset ? <Button
                                variant="contained" color="primary"
                                onClick={this.resetConditionHandler}
                                style={{ marginLeft: '10px', marginRight: '10px', verticalAlign: 'baseline' }}
                            >重置</Button> : ''
                        }
                    </div>
                </Col>
            </Row>
        );
    }
}

export default SearchBar;
