import { __assign, __extends } from "tslib";
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import cx from 'classnames';
import { Component, createRef } from 'react';
import getWidth from '../utils/getWidth';
import Point from './Point';
import Marks from './Marks';
import Dots from './Dots';
import { DisabledContext } from '../disabled';
import { getValue, toFixed, isLeftValue } from './common';
import NumberInput from '../number-input';
import { getPotentialValues, normalizeToPotentialValue } from './normalize';
import { WindowEventHandler } from '../utils/component/WindowEventHandler';
import withinRange from '../utils/withinRange';
export var getDecimal = function (step) {
    var fixed = String(step).split('.')[1];
    return fixed ? fixed.length : 0;
};
var getPosition = function (value, min, max) {
    var pos = ((value - min) * 100) / (max - min);
    return pos + "%";
};
function checkProps(props) {
    var range = props.range, value = props.value, max = props.max, min = props.min, dots = props.dots, marks = props.marks;
    if (range) {
        if (!Array.isArray(value)) {
            throw new Error('`value` must an array when `range` is true');
        }
        if (!(value.length === 2)) {
            throw new Error("value's length must as 2 when `range` is true");
        }
        if (!value.every(function (v) { return typeof v === 'number' && v >= min && v <= max; })) {
            throw new Error("value's each item must be a number and between min and max when `range` is true");
        }
        if (!(value[0] <= value[1])) {
            throw new Error('value[0] must be less than value[1] when `range` is true');
        }
    }
    else {
        if (typeof value !== 'number') {
            throw new Error('value must be an number when `range` is false');
        }
        if (value < min || value > max) {
            throw new Error('value must between min and max when `range` is false');
        }
    }
    if (dots) {
        if (!marks) {
            throw new Error('marks must be used with dots');
        }
    }
    if (marks && Object.keys(marks).length < 2) {
        throw new Error('at lease 2 marks needed');
    }
}
var Slider = (function (_super) {
    __extends(Slider, _super);
    function Slider() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.state = {
            decimal: getDecimal(_this.props.step),
            potentialValues: getPotentialValues(_this.props.marks),
            active: null,
            prevProps: _this.props,
        };
        _this.containerRef = createRef();
        _this.mouseDown = false;
        _this.limit = null;
        _this.isLeft = null;
        _this.onSingleChange = function (value) {
            if (_this.props.range !== false) {
                return;
            }
            var _a = _this.props, onChange = _a.onChange, dots = _a.dots, disabled = _a.disabled;
            var potentialValues = _this.state.potentialValues;
            var newValue = Number(value);
            if (dots) {
                newValue = normalizeToPotentialValue(potentialValues, newValue);
            }
            !disabled && onChange && onChange(newValue);
        };
        _this.onLeftChange = function (value) {
            if (_this.props.range !== true) {
                return;
            }
            var _a = _this.props, _b = _a.value, prevValue = _b === void 0 ? [0, 0] : _b, onChange = _a.onChange, dots = _a.dots, disabled = _a.disabled;
            var potentialValues = _this.state.potentialValues;
            if (disabled || !onChange) {
                return;
            }
            var newValue = Number(value);
            if (dots) {
                newValue = normalizeToPotentialValue(potentialValues, newValue);
            }
            var nextValue = newValue > prevValue[1]
                ? [prevValue[1], newValue]
                : [newValue, prevValue[1]];
            onChange(nextValue);
        };
        _this.onRightChange = function (value) {
            if (_this.props.range !== true) {
                return;
            }
            var _a = _this.props, _b = _a.value, prevValue = _b === void 0 ? [0, 0] : _b, onChange = _a.onChange, dots = _a.dots, disabled = _a.disabled;
            var potentialValues = _this.state.potentialValues;
            if (disabled || !onChange) {
                return;
            }
            var newValue = Number(value);
            if (dots) {
                newValue = normalizeToPotentialValue(potentialValues, newValue);
            }
            var nextValue = newValue > prevValue[0]
                ? [prevValue[0], newValue]
                : [newValue, prevValue[0]];
            onChange(nextValue);
        };
        _this.onMouseDown = function (e) {
            _this.mouseDown = true;
            var value = _this.getValueFromEvent(e);
            var _a = _this.props, min = _a.min, max = _a.max;
            var nextValue = withinRange(value, min, max);
            if (!_this.state.active) {
                _this.setState({
                    active: 'point-single',
                });
            }
            _this.onChange(nextValue);
        };
        _this.onWindowMouseUp = function () {
            _this.mouseDown = false;
            _this.limit = null;
            _this.isLeft = null;
            _this.setState({
                active: null,
            });
        };
        _this.onWindowMouseMove = function (e) {
            if (!_this.mouseDown) {
                return;
            }
            var nextValue = _this.getValueFromEvent(e);
            if (_this.props.range) {
                var _a = _this.props, value = _a.value, min = _a.min, max = _a.max;
                var left = void 0;
                if (value[0] === value[1]) {
                    left = e.movementX <= 0;
                }
                else {
                    left = isLeftValue(nextValue, value);
                }
                if (!_this.state.active) {
                    _this.setState({
                        active: left ? 'point-left' : 'point-right',
                    });
                }
                if (!_this.limit) {
                    _this.isLeft = left;
                    if (left) {
                        _this.limit = [min, value[1]];
                    }
                    else {
                        _this.limit = [value[0], max];
                    }
                }
                nextValue = withinRange(nextValue, _this.limit[0], _this.limit[1]);
            }
            else {
                var _b = _this.props, min = _b.min, max = _b.max;
                if (!_this.state.active) {
                    _this.setState({
                        active: 'point-single',
                    });
                }
                nextValue = withinRange(nextValue, min, max);
            }
            _this.onChange(nextValue);
        };
        return _this;
    }
    Slider.prototype.getComputedProps = function () {
        var _a = this.props, _b = _a.disabled, disabled = _b === void 0 ? this.context.value : _b, min = _a.min, max = _a.max;
        var decimal = this.state.decimal;
        if (this.props.range !== false) {
            var value = this.props.value;
            var leftPosition = getPosition(value[0], min, max);
            var leftProps = {
                min: min,
                max: value[1],
                disabled: disabled,
                decimal: decimal,
                onChange: this.onLeftChange,
                value: value[0],
                position: leftPosition,
            };
            var rightProps = {
                min: value[0],
                max: max,
                disabled: disabled,
                decimal: decimal,
                onChange: this.onRightChange,
                value: value[1],
                position: getPosition(value[1], min, max),
            };
            var width = (value[1] - value[0]) / (max - min);
            return {
                range: true,
                leftProps: leftProps,
                rightProps: rightProps,
                trackStyle: {
                    left: leftPosition,
                    width: width * 100 + "%",
                },
            };
        }
        var position = getPosition(this.props.value, min, max);
        return {
            range: false,
            props: {
                min: min,
                max: max,
                disabled: disabled,
                decimal: decimal,
                onChange: this.onSingleChange,
                value: this.props.value,
                position: position,
            },
            trackStyle: {
                left: 0,
                width: position,
            },
        };
    };
    Slider.prototype.onChange = function (rawValue) {
        var _a = this.props, dots = _a.dots, disabled = _a.disabled;
        var _b = this.state, potentialValues = _b.potentialValues, decimal = _b.decimal;
        if (disabled) {
            return;
        }
        var nextValue = toFixed(rawValue, decimal);
        if (dots) {
            nextValue = normalizeToPotentialValue(potentialValues, nextValue);
        }
        if (this.props.range === true) {
            var _c = this.props, onChange = _c.onChange, value = _c.value;
            if (!onChange) {
                return;
            }
            var isLeft = this.isLeft !== null ? this.isLeft : isLeftValue(rawValue, value);
            if (isLeft) {
                onChange([nextValue, value[1]]);
            }
            else {
                onChange([value[0], nextValue]);
            }
        }
        else {
            var onChange = this.props.onChange;
            onChange && onChange(nextValue);
        }
    };
    Slider.prototype.getValueFromEvent = function (e) {
        var _a = this.props, min = _a.min, max = _a.max;
        var el = this.containerRef.current;
        var ratio = (e.clientX - el.getBoundingClientRect().left) / el.clientWidth;
        var nextValue = getValue(ratio, min, max);
        return nextValue;
    };
    Slider.getDerivedStateFromProps = function (nextProps, _a) {
        var prevProps = _a.prevProps;
        if (nextProps === prevProps) {
            return null;
        }
        var state = {
            prevProps: nextProps,
        };
        if (prevProps.step !== nextProps.step) {
            state.decimal = getDecimal(nextProps.step);
        }
        if (prevProps.marks !== nextProps.marks) {
            state.potentialValues = getPotentialValues(nextProps.marks);
        }
        return state;
    };
    Slider.prototype.render = function () {
        if (process.env.NODE_ENV !== 'production') {
            checkProps(this.props);
        }
        var _a = this.props, withInput = _a.withInput, className = _a.className, width = _a.width, _b = _a.disabled, disabled = _b === void 0 ? this.context.value : _b, min = _a.min, max = _a.max, marks = _a.marks, dots = _a.dots;
        var _c = this.state, potentialValues = _c.potentialValues, active = _c.active;
        var computed = this.getComputedProps();
        return (_jsxs("div", __assign({ className: cx('zent-slider', className, {
                'zent-slider-disabled': disabled,
            }), style: getWidth(width), "data-zv": 'v10.0.11' }, { children: [_jsxs("div", __assign({ ref: this.containerRef, className: "zent-slider-main", onMouseDown: this.onMouseDown, "data-zv": 'v10.0.11' }, { children: [_jsx("div", { style: computed.trackStyle, className: cx('zent-slider-track', {
                                'zent-slider-track-disabled': disabled,
                            }), "data-zv": 'v10.0.11' }, void 0), computed.range === true ? (_jsxs(_Fragment, { children: [_jsx(Point, { active: active === 'point-left', disabled: disabled, position: computed.leftProps.position, value: computed.leftProps.value }, "point-left"), _jsx(Point, { active: active === 'point-right', disabled: disabled, position: computed.rightProps.position, value: computed.rightProps.value }, "point-right")] }, void 0)) : (_jsx(Point, { active: active === 'point-single', disabled: disabled, position: computed.props.position, value: computed.props.value }, "point-single")), marks ? (_jsxs(_Fragment, { children: [_jsx(Marks, { marks: marks, min: min, max: max, potentialValues: potentialValues }, void 0), dots ? (_jsx(Dots, { marks: marks, min: min, max: max, activeLeft: this.props.range === true ? this.props.value[0] : 0, activeRight: this.props.range === true
                                        ? this.props.value[1]
                                        : this.props.value, potentialValues: potentialValues, disabled: disabled }, void 0)) : null] }, void 0)) : null] }), void 0), withInput &&
                    !dots &&
                    (computed.range === true ? (_jsxs("div", __assign({ className: "zent-slider-input", "data-zv": 'v10.0.11' }, { children: [_jsx(NumberInput, __assign({}, computed.leftProps), "number-input-left"), _jsx("div", __assign({ className: "slider-input-line", "data-zv": 'v10.0.11' }, { children: "-" }), void 0), _jsx(NumberInput, __assign({}, computed.rightProps), "number-input-right")] }), void 0)) : (_jsx(NumberInput, __assign({ className: "zent-slider-input" }, computed.props), "number-input-single"))), _jsx(WindowEventHandler, { eventName: "mousemove", listener: this.onWindowMouseMove }, void 0), _jsx(WindowEventHandler, { eventName: "mouseup", listener: this.onWindowMouseUp }, void 0)] }), void 0));
    };
    Slider.defaultProps = {
        min: 0,
        max: 100,
        step: 1,
        withInput: true,
        range: false,
        value: 0,
    };
    Slider.contextType = DisabledContext;
    return Slider;
}(Component));
export { Slider };
