import { DatePicker, Space, TimePicker } from "antd";
import PropTypes from "prop-types";
import { useCallback, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors.js";
import dayjs from "../../utils/day";
import { fuzzyMatchDate } from "./formats.js";

const mapStateToProps = createStructuredSelector({
  bodyshop: selectBodyshop
});

const DateTimePicker = ({
  value,
  onChange,
  onBlur,
  id,
  onlyFuture,
  onlyToday,
  isDateOnly = false,
  isSeparatedTime = false,
  bodyshop,
  ...restProps
}) => {
  const [isManualInput, setIsManualInput] = useState(false);
  const { t } = useTranslation();

  const handleChange = useCallback(
    (newDate) => {
      if (onChange) {
        onChange(bodyshop?.timezone && newDate ? dayjs(newDate).tz(bodyshop.timezone, true) : newDate);
      }
      setIsManualInput(false);
    },
    [onChange, bodyshop?.timezone]
  );

  const handleBlur = useCallback(
    (e) => {
      // Bail if this is not a manual input
      if (!isManualInput) {
        return;
      }
      // Reset manual input flag
      setIsManualInput(false);

      const v = e?.target?.value;

      if (!v) return;

      let parsedDate = isDateOnly ? fuzzyMatchDate(v)?.startOf("day") : fuzzyMatchDate(v);

      if (parsedDate && onChange) {
        onChange(parsedDate);
      }
    },
    [isManualInput, isDateOnly, onChange]
  );

  const handleKeyDown = useCallback(
    (e) => {
      setIsManualInput(true);

      if (e.key.toLowerCase() === "t" && onChange) {
        e.preventDefault();
        setIsManualInput(false);
        onChange(dayjs());
      } else if (e.key.toLowerCase() === "enter") {
        handleBlur(e);
      }
    },
    [onChange, handleBlur]
  );

  const handleDisabledDate = useCallback(
    (current) => {
      if (onlyToday) {
        return !dayjs().isSame(current, "day");
      } else if (onlyFuture) {
        return dayjs().subtract(1, "day").isAfter(current);
      }
      return false;
    },
    [onlyToday, onlyFuture]
  );

  return (
    <div onKeyDown={handleKeyDown} id={id} style={{ width: "100%" }}>
      {isSeparatedTime && (
        <Space direction="vertical" style={{ width: "100%" }}>
          <DatePicker
            showTime={false}
            format="MM/DD/YYYY"
            value={value ? dayjs(value) : null}
            onChange={(dateValue) => {
              if (dateValue) {
                // When date changes, preserve the existing time if it exists
                if (value && dayjs(value).isValid()) {
                  const existingTime = dayjs(value);
                  const newDateTime = dayjs(dateValue)
                    .hour(existingTime.hour())
                    .minute(existingTime.minute())
                    .second(existingTime.second());
                  handleChange(newDateTime);
                } else {
                  // If no existing time, just set the date without time
                  handleChange(dateValue);
                }
              } else {
                handleChange(dateValue);
              }
            }}
            placeholder={t("general.labels.date")}
            onBlur={handleBlur}
            disabledDate={handleDisabledDate}
            isDateOnly={true}
            {...restProps}
          />
          {value && (
            <TimePicker
              format="hh:mm a"
              minuteStep={15}
              value={value && dayjs(value).hour() === 0 && dayjs(value).minute() === 0 ? null : dayjs(value)}
              defaultOpenValue={dayjs(value)
                .hour(dayjs().hour())
                .minute(Math.floor(dayjs().minute() / 15) * 15)
                .second(0)}
              onChange={(timeValue) => {
                if (timeValue) {
                  // When time changes, combine it with the existing date
                  const existingDate = dayjs(value);
                  const newDateTime = existingDate
                    .hour(timeValue.hour())
                    .minute(timeValue.minute())
                    .second(0);
                  handleChange(newDateTime);
                } else {
                  // If time is cleared, just update with null time but keep date
                  handleChange(timeValue);
                }
                if (onBlur) onBlur();
              }}
              placeholder={t("general.labels.time")}
              {...restProps}
            />
          )}
        </Space>
      )}
      {!isSeparatedTime && (
        <DatePicker
          showTime={
            isDateOnly
              ? false
              : {
                  format: "hh:mm a",
                  minuteStep: 15,
                  defaultValue: dayjs(dayjs(), "HH:mm:ss")
                }
          }
          format={isDateOnly ? "MM/DD/YYYY" : "MM/DD/YYYY hh:mm a"}
          value={value ? dayjs(value) : null}
          onChange={handleChange}
          placeholder={isDateOnly ? t("general.labels.date") : t("general.labels.datetime")}
          onBlur={onBlur || handleBlur}
          disabledDate={handleDisabledDate}
          {...restProps}
        />
      )}
    </div>
  );
};

DateTimePicker.propTypes = {
  value: PropTypes.any,
  onChange: PropTypes.func,
  onBlur: PropTypes.func,
  id: PropTypes.string,
  onlyFuture: PropTypes.bool,
  onlyToday: PropTypes.bool,
  isDateOnly: PropTypes.bool,
  isSeparatedTime: PropTypes.bool
};

export default connect(mapStateToProps, null)(DateTimePicker);
