import { h, Component, render } from 'preact'
import { isFunction, isArray, safety, deepMerge, mergeArr, IEVersion } from '@/common/util'

const emptyVal = {};

/**
 * 普通的多选渲染
 */
class General extends Component{

	constructor(options){
		super(options);

		this.setState({
			filterValue: '',
			remote: true,
			loading: false,
			pageIndex: 1,
			totalSize: 0,
			val: emptyVal,
		});

		this.searchCid = 0;
		this.inputOver = true;
		this.__value = '';
		this.tempData = [];
		this.size = 0;
	}

	optionClick(item, selected, disabled, e){
		this.props.ck(item, selected, disabled);
		this.focus();
		//阻止父组件上的事件冒泡
		this.blockClick(e);
	}

	groupClick(item, e){
		const { click, children, disabled } = this.props.prop;
		let m = item[click], arr = item[children].filter(opt => !opt[disabled]);

		if(m === 'SELECT'){
			this.props.onReset(arr, 'append');
		}else if(m === 'CLEAR'){
			this.props.onReset(arr, 'delete');
		}else if(m === 'AUTO'){
			this.props.onReset(arr, 'auto');
		}else if(isFunction(m)){
			m(item);
		}
		this.focus();
		//阻止父组件上的事件冒泡
		this.blockClick(e);
	}

	blockClick(e){
		e.stopPropagation();
	}

	pagePrevClick(size = this.size){
		let index = this.state.pageIndex;
		if(index <= 1){
			return ;
		}
		this.changePageIndex(index - 1);
		this.props.pageRemote && this.postData(index - 1, true);
	}
	pageNextClick(size = this.size){
		let index = this.state.pageIndex;
		if(index >= size){
			return ;
		}
		this.changePageIndex(index + 1);
		this.props.pageRemote && this.postData(index + 1, true);
	}

	changePageIndex(index){
		this.setState({
			pageIndex: index
		})
	}

	labelSearch(e){
		if(e.type == 'input'){
			this.searchInput(e)
		}else{
			this.handleComposition(e)
		}
	}

	searchInput(e){
		let v = e.target.value;

		if(v === this.__value){
			return ;
		}

		this.searchCid && clearTimeout(this.searchCid);
		if(this.inputOver){
			//保证输入框内的值是实时的
			this.__value = v;

			//让搜索变成异步的
			this.searchCid = setTimeout(() => {
				this.callback = true;
				this.setState({ filterValue: this.__value, remote: true, pageIndex: 1 })
			}, this.props.delay);
		}
	}

	focus(){
		this.searchInputRef && this.searchInputRef.focus();
	}

	blur(){
		this.searchInputRef && this.searchInputRef.blur();
	}

	handleComposition(e){
		let type = e.type;

		if(type === 'compositionstart'){
			this.inputOver = false;
			this.searchCid && clearTimeout(this.searchCid);
		}else if(type === 'compositionend'){
			this.inputOver = true;
			this.searchInput(e);
		}
	}

	postData(pageIndex = this.state.pageIndex, mandatory = false){
		if(this.state.remote || mandatory){
			this.callback = false;
			this.setState({ loading: true, remote: false });
			//让输入框失去焦点
			this.blur();
			this.props.remoteMethod(this.state.filterValue, (result, totalSize = 1) => {
				//这里同步修改为异步
				setTimeout(() => {
					//回调后可以重新聚焦
					this.focus();
					this.callback = true;
					this.setState({ loading: false, totalSize });
					this.props.onReset(result, 'data');
				}, 10);
			}, this.props.show, pageIndex);
		}
	}

	//键盘事件
	keydown(type, e){
		let keyCode = e.keyCode;

		if(type === 'div'){
			//Esc, Tab
			if(keyCode === 27 || keyCode === 9){
				this.props.onReset(false, 'close');
			}else
			//Left
			if(keyCode === 37){
				this.pagePrevClick();
			}else
			//Right 键
			if(keyCode === 39){
				this.pageNextClick();
			}
		}

		if(this.props.enableKeyboard){
			const { value, optgroup, disabled } = this.props.prop;
			let data = this.tempData.filter(item => !item[optgroup] && !item[disabled]);
			let len = data.length - 1;
			if(len === -1){
				return ;
			}

			let index = data.findIndex(item => item[value] === this.state.val);
			//Up 键
			if(keyCode === 38){
				if(index <= 0){
					index = len
				}else if(index > 0){
					index -= 1;
				}
				let val = data[index][value];
				this.setState({ val })
				this.viewTo(val);
			}else
			//Down 键
			if(keyCode === 40){
				if(index === -1 || index === len){
					index = 0
				}else if(index < len){
					index += 1;
				}
				let val = data[index][value];
				this.setState({ val })
				this.viewTo(val);
			}else
			//Enter 键
			if(keyCode === this.props.selectedKeyCode){
				if(this.state.val != emptyVal){
					let option = data[index];
					this.optionClick(option, this.props.sels.findIndex(item => item[value] === this.state.val) != -1, option[disabled], e)
				}
			}
		}
	}

	viewTo(val){
		//键盘选中时滚动到可视范围内
		if(void 0 != this.base){
			let opt = this.base.querySelector(`.xm-option[value="${ val }"]`);
			opt && opt.scrollIntoView(false)
		}
	}

	//组件将要接收新属性
	componentWillReceiveProps(props){
		if(this.props.show != props.show){
			if(!props.show){
				//清空输入框的值
				this.setState({ filterValue: '', val: emptyVal });
				this.__value = '';
				this.searchInputRef && (this.searchInputRef.value = '');
				this.props.onReset('', 'labelSearchBlur')
			}else{
				//聚焦输入框
				setTimeout(() => {
					if(props.model.label.type === 'search'){

					}else if(props.filterable){
						this.focus()
					}else{
						this.base.focus()
					}
				}, 0);
			}
		}
		if(this.props.__update != props.__update){
			this.setState({ remote: true })
		}
	}

	render(config) {
		let { data, flatData, prop, template, theme, radio, sels, empty, filterable, filterMethod, remoteSearch, remoteMethod, delay, searchTips, create, pageRemote, max, enableKeyboard, enableHoverFirst } = config

		const { name, value, disabled, children, optgroup } = prop;

		let arr = deepMerge([], flatData), creator;

		//远程分页 或者 远程搜索
		if(pageRemote || filterable && remoteSearch){
			this.postData();
		}

		//本地搜索
		if(filterable && !(remoteSearch || pageRemote)){
			const filterData = (item, index) => {
				const isGroup = item[optgroup];
				if(isGroup){
					delete item.__del;
					return true;
				}
				return filterMethod(this.state.filterValue, item, index, prop);
			}
			arr = arr.filter(filterData);

			for(let i = 0; i < arr.length - 1; i++){
				let a = arr[i];
				let b = arr[i + 1];
				if(a[optgroup] && b[optgroup]){
					arr[i].__del = true;
				}
			}
			if(arr.length && arr[arr.length - 1][optgroup]){
				arr[arr.length - 1].__del = true;
			}
			arr = arr.filter(item => !item.__del);
			//创建条目
			creator = this.state.filterValue && isFunction(create);
		}

		const search = (
			<div class={ filterable && config.model.label.type != 'search' ? 'xm-search' : 'xm-search dis' }>
				<i class="xm-iconfont xm-icon-sousuo"></i>
				<input class="xm-input xm-search-input" placeholder={ searchTips } />
			</div>
		);

		//如果是分组模式, 要分页先去除分组, 然后在计算分页, 最后再加上分组
		let groupInfo = {};
		arr.filter(item => item[optgroup]).forEach((g, groupIndex) => {
			groupInfo[groupIndex] = g;
			g[children].forEach(item => item.__group__index = groupIndex);
		});
		arr = arr.filter(item => !item[optgroup]);

		let paging = '';
		if(config.paging){
			//计算当前分页的总页码
			let size = pageRemote ? this.state.totalSize : Math.floor((arr.length - 1) / config.pageSize) + 1;
			size <= 0 && (size = 1);

			let pageIndex = this.state.pageIndex;

			//如果当前页码大于总页码, 重置一下
			if(pageIndex > size){
				pageIndex = size;
			}

			//如有总页码>1, 但是因为搜索造成的页码=0的情况
			if(size > 0 && pageIndex <= 0){
				pageIndex = 1;
			}

			if(!pageRemote){
				//实现简单的物理分页
				let start = (pageIndex - 1) * config.pageSize;
				let end = start + config.pageSize;
				arr = arr.slice(start, end);
			}

			const disabledStyle = {cursor: 'no-drop', color: '#d2d2d2'};

			let prevStyle = {}, nextStyle = {};
			pageIndex <= 1 && (prevStyle = disabledStyle);
			pageIndex == size && (nextStyle = disabledStyle);

			this.state.pageIndex !== pageIndex && this.changePageIndex(pageIndex);
			this.size = size;

			paging = (
				<div class='xm-paging'>
					<span style={ prevStyle } onClick={ this.pagePrevClick.bind(this, size) }>{ config.languageProp.paging.prev }</span>
					<span>{ this.state.pageIndex } / { size }</span>
					<span style={ nextStyle } onClick={ this.pageNextClick.bind(this, size) }>{ config.languageProp.paging.next }</span>
				</div>
			)
		}else{
			//检查是否设置了显示数量上限
			if(config.showCount > 0){
				arr = arr.slice(0, config.showCount);
			}
		}

		let newArr = [], group, tmpGroup = { __tmp: true };
		tmpGroup[optgroup] = true;
		arr.forEach(item => {
			let g = groupInfo[item.__group__index];
			delete item.__group__index;
			if(group && !g){
				g = tmpGroup
			}
			if(g != group){
				group = g;
				g && newArr.push(group);
			}
			newArr.push(item);
		});
		arr = newArr;

		//查看是否创建了条目
		if(creator){
			creator = create(this.state.filterValue, deepMerge([], arr));
			if(void 0 != creator){
				arr.splice(0, 0, ...(isArray(creator) ? creator : [creator]).map(i => ({ ...i, __node: {} })));
			}
		}

		let safetyArr = deepMerge([], arr);
		this.tempData = safetyArr;

		//工具条操作
		const toolbar = (
			<div class='xm-toolbar'>
				{ config.toolbar.list.map(tool => {
					const toolClass = 'toolbar-tag';
					const toolStyle = {};

					let info, name = config.languageProp.toolbar[tool];
					if(tool === 'ALL'){
						info = { icon: 'xm-iconfont xm-icon-quanxuan', name, method: (pageData) => {
							const { optgroup, disabled } = prop;
							const list = pageData.filter(item => !item[optgroup]).filter(item => !item[disabled])

							const disSels = sels.filter(item => item[prop.disabled]);
							let result = [];
							//单选的处理
							if(radio){
								result = disSels.length ? disSels : list.slice(0, 1)
							}else if(max > 0){
								result = disSels.length >= max ? disSels : mergeArr(list.slice(0, max - disSels.length), disSels, prop)
							}else{
								result = mergeArr(list, sels, prop)
							}

							this.props.onReset(result, 'sels');
						} };
					}else if(tool === 'CLEAR'){
						info = { icon: 'xm-iconfont xm-icon-qingkong', name, method: (pageData) => {
							this.props.onReset(sels.filter(item => item[prop.disabled]), 'sels');
						} };
					}else if(tool === 'REVERSE'){
						info = { icon: 'xm-iconfont xm-icon-fanxuan', name, method: (pageData) => {
							const { optgroup, disabled } = prop;
							const list = pageData.filter(item => !item[optgroup]).filter(item => !item[disabled])

							let selectedList = [];
							sels.forEach(item => {
								let index = list.findIndex(pageItem => pageItem[value] === item[value]);
								if(index == -1){
									selectedList.push(item);
								}else{
									list.splice(index, 1);
								}
							})

							const disSels = selectedList.filter(item => item[prop.disabled]);
							let result = [];
							//单选的处理
							if(radio){
								result = disSels.length ? disSels : list.slice(0, 1)
							}else if(max > 0){
								result = disSels.length >= max ? disSels : mergeArr(list.slice(0, max - disSels.length), disSels, prop)
							}else{
								result = mergeArr(list, selectedList, prop)
							}

							this.props.onReset(result, 'sels');
						} };
					}else {
						info = tool
					}

					const hoverChange = e => {
						if(e.type === 'mouseenter') e.target.style.color = theme.color;
						if(e.type === 'mouseleave') e.target.style.color = '';
					}

					return (<div class={ toolClass } style={ toolStyle } onClick={ () => {
						isFunction(info.method) && info.method(safetyArr)
						this.focus()
					} } onMouseEnter={ hoverChange } onMouseLeave={ hoverChange }>
						{ config.toolbar.showIcon && <i class={ info.icon }></i> }
						<span>{ info.name }</span>
					</div>)
				}).filter(a => a) }
			</div>
		)

		const showIcon = config.model.icon != 'hidden';
		const renderItem = item => {
			const selected = !!sels.find(sel => sel[value] == item[value])
			const iconStyle = selected ? {
				color: theme.color,
				border: 'none'
			} : {
				borderColor: theme.color,
			};
			const itemStyle = {}

			//处理键盘的选择背景色
			if(enableKeyboard && item[value] === this.state.val){
				itemStyle.backgroundColor = theme.hover
			}
			//不显示图标时候的背景色处理
			if(!showIcon && selected){
				itemStyle.backgroundColor = theme.color;
				item[disabled] && (itemStyle.backgroundColor = '#C2C2C2');
			}
			const className = ['xm-option', (item[disabled] ? ' disabled' : ''), (selected ? ' selected' : ''), (showIcon ? 'show-icon' : 'hide-icon') ].join(' ');
			const iconClass = ['xm-option-icon', (() => {
				let selectICON = config.iconfont.select;
				let unselectICON = config.iconfont.unselect;
				if(selectICON){
					return !selected && unselectICON ? unselectICON + ' xm-custom-icon' : selectICON;
				}
				return 0;
			})() || ('xm-iconfont ' + (radio ? 'xm-icon-danx' : 'xm-icon-duox'))].join(' ');

			//处理鼠标选择的背景色
			const hoverChange = e => {
				if(e.type === 'mouseenter'){
					if(!item[disabled]){
						if(enableKeyboard){
							this.setState({ val: item[value] })
						}else{
							e.target.style.backgroundColor = theme.hover;
						}
					}
				}else if(e.type === 'mouseleave'){
					if(!item[disabled]){
						if(enableKeyboard){

						}else{
							e.target.style.backgroundColor = '';
						}
					}
				}
			}

			return (
				<div class={ className } style={ itemStyle } value={ item[value] } onClick={
					this.optionClick.bind(this, item, selected, item[disabled])
				} onMouseEnter={ hoverChange } onMouseLeave={ hoverChange }>
					{ showIcon && <i class={ iconClass } style={ iconStyle }></i> }
					<div class='xm-option-content' dangerouslySetInnerHTML={{ __html: template({ data, item, arr: sels, name: item[name], value: item[value] }) }}></div>
				</div>
			)
		}

		const renderGroup = item => {
			const isGroup = item[optgroup];
			if(isGroup){//分组模式
				if(item.__tmp){
					return <div class="item--divided"></div>
				}
				return (
					<div class="xm-group">
						<div class="xm-group-item" onClick={ this.groupClick.bind(this, item) }>{ item[name] }</div>
					</div>
				)
			}
			return renderItem(item);
		}

		arr = arr.map(renderGroup);

		if(arr.length){
			if(enableHoverFirst && this.state.val == emptyVal){
				this.keydown('div', { keyCode: 40 })
			}
		}else{
			//查看无数据情况下是否显示分页
			!config.pageEmptyShow && (paging = '');
			arr.push(<div class="xm-select-empty">{ empty }</div>)
		}

		return (
			<div onClick={ this.blockClick } tabindex="1" style="outline: none;">
				<div>
					{ config.toolbar.show && toolbar }
					{ search }
					<div class="scroll-body" style={ {maxHeight: config.height} }>{ arr }</div>
					{ config.paging && paging }
				</div>
				{ this.state.loading && <div class="loading" >
					<span class="loader"></span>
				</div> }
			</div>
		)
	}

	//组件完成挂载
	componentDidMount(){
		let input = this.base.querySelector('.xm-search-input');
		if(input){
			input.addEventListener('compositionstart', this.handleComposition.bind(this));
			input.addEventListener('compositionupdate', this.handleComposition.bind(this));
			input.addEventListener('compositionend', this.handleComposition.bind(this));
			input.addEventListener('input', this.searchInput.bind(this));
			this.searchInputRef = input;
		}
		this.base.addEventListener('keydown', this.keydown.bind(this, 'div'));
	}

	//此时页面又被重新渲染了
	componentDidUpdate(){
		if(this.callback){
			this.callback = false;

			let done = this.props.filterDone;
			if(isFunction(done)){
				done(this.state.filterValue, this.tempData || []);
			}
		}
	}

}

export default General;
