import * as React from 'react';
import { ValidationRule, Validation } from '../../models/Validation';
import { sliderData } from './../../models/slider';
import { Query } from '../../models/query';

export interface SliderProps {
	label?: string;
	type?: string;
	name?: string;
	validationStates?: { [name: string]: Validation };
	placeholder?: string;
	validationRules?: Array<ValidationRule>;
	onOptionClick?: (option: any) => void;
	required?: boolean;
	value?: number;
	onChange?: (name: string, value: number) => void;
	footerFormatter?: (value: number) => string;
	sliderData?: sliderData;
	query?: Query;
	errorMessage?: {
		min: string;
		max: string;
	};
}

type SliderContainer = SliderProps & {
	render: (
		sliderOnChange: (value: string) => void,
		inputOnBlur: (value: string) => void,
		inputOnChange: (name: string, value: string) => void,
		inputOnKeyDown: (value: string, e: React.KeyboardEvent<HTMLInputElement>) => void,
		stepUp: () => void,
		stepDown: () => void,
		inputValue: number,
		errorMessage?: React.ReactNode
	) => JSX.Element;
};

interface SliderState {
	inputValue: number;
	errorMessage?: React.ReactNode;
}

class Slider extends React.Component<SliderContainer, SliderState> {
	constructor(props: SliderContainer) {
		super(props);
		this.state = {
			inputValue: this.props.value
		};
	}

	shouldComponentUpdate(nextProps: SliderProps, nextState: SliderState) {
		return (
			this.props.value !== nextProps.value ||
			this.state.inputValue !== nextState.inputValue ||
			this.props.query !== nextProps.query
		);
	}

	sliderOnChange = (value: string | number) => {
		let errorMessage: React.ReactNode = '';
		if (+value > this.props.sliderData.max) {
			value = String(this.props.sliderData.max);
			errorMessage = this.props.errorMessage.max;
		}
		if (+value < this.props.sliderData.min) {
			value = String(this.props.sliderData.min);
			errorMessage = this.props.errorMessage.min;
		}

		this.setState({
			inputValue: +value,
			errorMessage
		});
		this.props.onChange(this.props.name, +value);
	};

	inputOnChange = (name: string, value: string) => {
		if (isNaN(+value)) return;
		this.setState({
			inputValue: +value
		});
	};

	inputOnBlur = (value: string) => {
		this.sliderOnChange(
			String(Math.floor(+value / this.props.sliderData.step) * this.props.sliderData.step)
		);
	};

	inputOnKeyDown = (value: string, e: React.KeyboardEvent<HTMLInputElement>) => {
		if (e.keyCode === 13) {
			//enter
			e.preventDefault();
			this.inputOnBlur(value);
		}
	};

	stepUp = () => {
		let newValue = this.props.value + this.props.sliderData.step;
		if (newValue <= this.props.sliderData.max) {
			this.sliderOnChange(newValue);
		}
	};

	stepDown = () => {
		let newValue = this.props.value - this.props.sliderData.step;
		if (newValue >= this.props.sliderData.min) {
			this.sliderOnChange(newValue);
		}
	};

	render() {
		return this.props.render(
			this.sliderOnChange,
			this.inputOnBlur,
			this.inputOnChange,
			this.inputOnKeyDown,
			this.stepUp,
			this.stepDown,
			this.state.inputValue,
			this.state.errorMessage
		);
	}
}

export default Slider;
