import React, { forwardRef, useCallback, useMemo, useRef, useState, useEffect, useImperativeHandle } from 'react';
import { StyleSheet, Text } from 'react-native';
import MpxPickerView from '../mpx-picker-view';
import MpxPickerViewColumn from '../mpx-picker-view-column';
import { useUpdateEffect } from '../utils';
import { years, months, daysInMonth, wrapDate, daysInMonthLength, START_YEAR, END_YEAR } from './dateData';
const START_DATE = `${START_YEAR}-01-01`;
const END_DATE = `${END_YEAR}-12-31`;
const START_DATE_ARR = [START_YEAR, 1, 1];
const END_DATE_ARR = [END_YEAR, 12, 31];
const styles = StyleSheet.create({
    pickerContainer: {
        height: 240,
        paddingHorizontal: 10,
        borderTopLeftRadius: 10,
        borderTopRightRadius: 10
    },
    pickerIndicator: {
        height: 45
    },
    pickerItem: {
        fontSize: 16,
        lineHeight: 45,
        textAlign: 'center'
    }
});
const getColumnLength = (fields = 'day') => {
    return fields === 'year' ? 1 : fields === 'month' ? 2 : 3;
};
const compareDateStr = (date1, date2) => {
    const [y1 = START_YEAR, m1 = 0, d1 = 0] = typeof date1 === 'string' ? date1.split('-').map(Number) : date1;
    const [y2 = START_YEAR, m2 = 0, d2 = 0] = typeof date2 === 'string' ? date2.split('-').map(Number) : date2;
    const num1 = y1 * 10000 + m1 * 100 + d1;
    const num2 = y2 * 10000 + m2 * 100 + d2;
    if (num1 === num2) {
        return 0;
    }
    return num1 > num2 ? 1 : -1;
};
const getDateArr = (date) => {
    const [y, m, d] = typeof date === 'string' ? date.split('-').map(Number) : date;
    return [y || 0, m || 0, d || 0];
};
const calibrateDate = (date, start, end) => {
    let startArr = getDateArr(start);
    let endArr = getDateArr(end);
    let dateArr = getDateArr(date);
    if (compareDateStr(startArr, endArr) > 0) {
        startArr = START_DATE_ARR;
    }
    if (compareDateStr(endArr, startArr) < 0) {
        endArr = END_DATE_ARR;
    }
    if (compareDateStr(start, end) > 0) {
        startArr = START_DATE_ARR;
        endArr = END_DATE_ARR;
    }
    if (compareDateStr(dateArr, endArr) > 0) {
        dateArr = endArr;
    }
    if (compareDateStr(dateArr, startArr) < 0) {
        dateArr = startArr;
    }
    return dateArr;
};
const initDateStr2Arr = (dateStr, start, end) => {
    if (!dateStr) {
        const today = new Date();
        const todayYear = today.getFullYear();
        const todayMonth = today.getMonth() + 1;
        const todayDay = today.getDate();
        dateStr = [todayYear, todayMonth, todayDay];
    }
    const [y, m, d] = getDateArr(dateStr);
    const year = Math.min(Math.max(START_YEAR, y), END_YEAR);
    const month = Math.min(Math.max(1, m), 12);
    const day = Math.min(Math.max(1, d), daysInMonthLength(year, month));
    const res = [year, month, day];
    return calibrateDate(res, start, end);
};
const valueStr2Obj = (_value = '', // eg: 2025-2-12
limit, start, end) => {
    const [y, m, d] = initDateStr2Arr(_value, start, end);
    const ans = {
        indexArr: [y - START_YEAR],
        rangeArr: [years]
    };
    if (limit === 2) {
        ans.indexArr.push(m - 1);
        ans.rangeArr.push(months);
    }
    else if (limit === 3) {
        const days = daysInMonth(y, m);
        ans.indexArr.push(m - 1, d - 1);
        ans.rangeArr.push(months, days);
    }
    return ans;
};
const valueChanged2Obj = (currentObj, value, limit = 3) => {
    const currentValue = currentObj.indexArr;
    const rangeArr = currentObj.rangeArr;
    if (limit === 3 && (currentValue[0] !== value[0] || currentValue[1] !== value[1])) {
        const days = daysInMonth(value[0], value[1] + 1);
        rangeArr[2] = days;
        const maxIndex = days.length - 1;
        if (value[2] > maxIndex) {
            value[2] = maxIndex;
        }
    }
    return {
        indexArr: value,
        rangeArr
    };
};
const valueChanged2Obj2 = (value, limit = 3, start, end) => {
    const y = value[0] + START_YEAR;
    const m = value[1] + 1;
    const d = value[2] + 1;
    return valueStr2Obj([y, m, d], limit, start, end);
};
const valueNum2String = (value) => {
    return value.map((item, index) => {
        if (index === 0) {
            return item + START_YEAR;
        }
        else {
            return wrapDate()(item + 1);
        }
    }).join('-');
};
const hasDiff = (currentValue, value, limit = 3) => {
    for (let i = 0; i < limit; i++) {
        if (currentValue[i] !== value[i]) {
            return true;
        }
    }
    return false;
};
const PickerDate = forwardRef((props, ref) => {
    const { value = '', start = START_DATE, end = END_DATE, fields, bindchange } = props;
    const nodeRef = useRef(null);
    const columnLength = useMemo(() => getColumnLength(fields), [fields]);
    const [formatObj, setFormatObj] = useState(valueStr2Obj(value, columnLength, start, end));
    const timerRef = useRef(null);
    useEffect(() => {
        return () => {
            timerRef.current && clearTimeout(timerRef.current);
        };
    }, []);
    useUpdateEffect(() => {
        const calibratedValue = valueStr2Obj(value, columnLength, start, end);
        setFormatObj(calibratedValue);
    }, [value, columnLength, start, end]);
    const updateValue = useCallback((value = '') => {
        const calibratedValue = valueStr2Obj(value, columnLength, start, end);
        setFormatObj(calibratedValue);
    }, [columnLength, start, end]);
    const _props = useRef(props);
    _props.current = props;
    useImperativeHandle(ref, () => ({
        updateValue,
        getNodeInstance: () => ({
            props: _props,
            nodeRef,
            instance: {
                style: {}
            }
        })
    }));
    const onChange = useCallback((e) => {
        const { value } = e.detail;
        const currentValue = formatObj.indexArr;
        const newObj = valueChanged2Obj(formatObj, value, columnLength);
        if (hasDiff(currentValue, value, columnLength)) {
            setFormatObj(newObj);
            const newObj2 = valueChanged2Obj2(value, columnLength, start, end);
            if (hasDiff(newObj.indexArr, newObj2.indexArr, columnLength)) {
                timerRef.current && clearTimeout(timerRef.current);
                timerRef.current = setTimeout(() => setFormatObj(newObj2));
            }
        }
        bindchange?.({ detail: { value: valueNum2String(newObj.indexArr) } });
    }, [formatObj, columnLength, bindchange, start, end]);
    const renderColumn = () => {
        return formatObj.rangeArr?.map((item, index) => (
        // @ts-expect-error ignore
        <MpxPickerViewColumn key={index}>
        {item.map((item, index) => {
                return <Text key={index} style={styles.pickerItem}>
            {item}
          </Text>;
            })}
      </MpxPickerViewColumn>));
    };
    return (<MpxPickerView style={styles.pickerContainer} indicator-style={styles.pickerIndicator} value={formatObj.indexArr} bindchange={onChange}>
      {renderColumn()}
    </MpxPickerView>);
});
PickerDate.displayName = 'MpxPickerDate';
export default PickerDate;
