import "./FormListTimeRangeField.scss";
import React, { useMemo } from "react";
import { Button, Col, Row } from "antd";
import { Text } from "../Typography";
import { ReactComponent as AddIcon } from "../../icons/add.svg";
import { ReactComponent as TrashIcon } from "../../icons/trash.svg";
import { Field, FieldArray, FormikProps } from "formik";
import { AntTimeRangePicker } from "./FieldItemTimeRangePicker";
import classNames from "classnames";
import moment from "moment";
import * as MomentTZ from "moment";
const momentTZ = extendMoment(MomentTZ);
import { useCallback } from "react";
import { isSameDay } from "utils";
import notification from "utils/notification";
import { Icon } from "components/Icon";
import { extendMoment } from "moment-range";

export interface FieldTimeRange {
  id?: string;
  startTime: moment.Moment;
  endTime: moment.Moment;
}

export interface FormTimeRangeValues {
  selectedDate?: moment.Moment[];
  periods: FieldTimeRange[];
}

interface Props extends FormikProps<FormTimeRangeValues> {
  isBooked?: boolean;
  addtext?: string;
  label?: string;
  description?: string;
  labelClassName?: string;
  descriptionClassName?: string;
  disableAdd?: boolean;
  disableUpdate?: boolean;
  disableRemove?: boolean;
  selectedTimeZone: string;
  bookingDates: string[];
  onAdd?: (value: FieldTimeRange, selectedDate: moment.Moment[]) => void;
  onRemove?: (
    index: number,
    value: FieldTimeRange,
    selectedDate: moment.Moment[]
  ) => void;
  onEdit?: (
    index: number,
    oldvalue: FieldTimeRange,
    newvalue: FieldTimeRange,
    selectedDate: moment.Moment[]
  ) => void;
}

export const FieldTimeRange: React.FC<Props> = ({
  isBooked,
  bookingDates,
  description,
  label,
  labelClassName,
  descriptionClassName,
  addtext = "Add New Time",
  values,
  errors,
  selectedTimeZone,
  onAdd,
  onRemove,
  onEdit,
}) => {
  const isDisableAddNew = useMemo(() => {
    if (!values.selectedDate || !values.selectedDate.length) return true;
    return false;
  }, [values.selectedDate]);

  const checkIsDisableEditOrRemove = useCallback(
    (value: FieldTimeRange) => {
      if (!values?.selectedDate || !isBooked) return false;
      const rangeCheck = momentTZ.range(value.startTime, value.endTime);
      // if this period contains bookingdate => period were locked
      const isExistBooking = bookingDates?.find((d) =>
        rangeCheck.contains(momentTZ.tz(d, selectedTimeZone))
      );
      if (isExistBooking && isBooked) {
        return true;
      }
      return false;
    },
    [bookingDates, values, isBooked, selectedTimeZone]
  );

  const getErrorMessage = useCallback(
    (index) => {
      if ((errors.periods as any)?.[index]?.startTime) {
        return (errors.periods as any)?.[index]?.startTime;
      } else if ((errors.periods as any)?.[index]?.endTime) {
        return (errors.periods as any)?.[index]?.endTime;
      }
      return null;
    },
    [errors]
  );

  const handleAddRange = useCallback(
    (push: any) => {
      const selectedDate = values.selectedDate?.[0] as moment.Moment;

      if (!selectedDate) {
        notification.warn({
          message: "Please select a day to add the times ranges.",
        });
        return;
      }

      const startTime = selectedDate.clone().startOf("day").hours(9).minutes(0);

      let timeRange = {
        startTime: startTime,
        endTime: startTime.clone().add(30, "minutes"),
      };

      if (values.periods.length > 0) {
        const lastRange = values.periods[values.periods.length - 1];
        const endTime = lastRange.endTime.clone();
        const nextStartTime = moment(endTime).add(30, "minutes");
        const nextEndTime = moment(endTime).add(60, "minutes");

        if (nextStartTime.isValid() && nextEndTime.isValid()) {
          timeRange = {
            startTime: nextStartTime,
            endTime: nextEndTime,
          };
        }
      }

      if (isSameDay(timeRange.startTime, selectedDate)) {
        push(timeRange);
        onAdd && onAdd(timeRange, values.selectedDate || []);
      } else {
        notification.warn({
          message: "Out of times.",
        });
      }
    },
    [values]
  );

  const handleEditRange = useCallback(
    (
      replace: any,
      index: number,
      oldvalue: FieldTimeRange,
      newvalue: FieldTimeRange
    ) => {
      replace(index, newvalue);
      onEdit && onEdit(index, oldvalue, newvalue, values.selectedDate || []);
    },
    [values]
  );

  const handleRemoveRange = useCallback(
    (remove: any, index: number, value: FieldTimeRange) => {
      remove(index);
      onRemove && onRemove(index, value, values.selectedDate || []);
    },
    [values]
  );

  return (
    <React.Fragment>
      {label && (
        <Text className={classNames("d--block", labelClassName)}>{label}</Text>
      )}
      {description && (
        <Text className={classNames("d--block m__b--8", descriptionClassName)}>
          {description}
        </Text>
      )}
      <FieldArray name="periods">
        {({ remove, replace, push }) => (
          <React.Fragment>
            {values.periods.length > 0 &&
              values.periods.map((field: FieldTimeRange, index: number) => {
                const isDisableEditOrRemove = checkIsDisableEditOrRemove(field);
                return (
                  <Row key={index} align="middle" className="m__b--8">
                    <Col span={11}>
                      <Field
                        hasError={(errors.periods as any)?.[index]?.startTime}
                        value={field.startTime}
                        name={`periods.${index}.startTime`}
                        component={AntTimeRangePicker}
                        disabled={isDisableEditOrRemove}
                        onBlur={(value: moment.Moment) =>
                          handleEditRange(replace, index, field, {
                            ...field,
                            startTime: value,
                          })
                        }
                      />
                    </Col>
                    <Col span={1} className="text__align--center">
                      -
                    </Col>
                    <Col span={11}>
                      <Field
                        hasError={(errors.periods as any)?.[index]?.endTime}
                        value={field.endTime}
                        name={`periods.${index}.endTime`}
                        component={AntTimeRangePicker}
                        disabled={isDisableEditOrRemove}
                        onBlur={(value: moment.Moment) =>
                          handleEditRange(replace, index, field, {
                            ...field,
                            endTime: value,
                          })
                        }
                      />
                    </Col>
                    <Col span={1} className="text__align--center">
                      <Button
                        disabled={isDisableEditOrRemove}
                        type="text"
                        className={classNames({
                          "btn-remove-item": true,
                          "btn-remove-item__disabled": isDisableEditOrRemove,
                        })}
                      >
                        <TrashIcon
                          style={{ cursor: "pointer" }}
                          onClick={() => {
                            handleRemoveRange(remove, index, field);
                          }}
                        />
                      </Button>
                    </Col>
                    {isDisableEditOrRemove && (
                      <Col span={24} className="m__t--6">
                        <div className="d--flex align__items--center">
                          <Icon name="warning" width={18} height={18} />
                          <Text
                            preset="regular14"
                            className="m__l--10 text__line-height--22"
                          >
                            Someone has made a booking during this slot so it
                            cannot be deleted or changed
                          </Text>
                        </div>
                      </Col>
                    )}
                    <Col span={12}>
                      {getErrorMessage(index) && (
                        <div className="field-error">
                          {getErrorMessage(index)}
                        </div>
                      )}
                    </Col>
                  </Row>
                );
              })}
            <div
              className="form-list__actions text--blue d--flex align__items--center m__t--20"
              style={{ width: 120 }}
            >
              <Button
                disabled={isDisableAddNew}
                type="text"
                className="btn-add-item d--flex align__items--center p__l--0"
                onClick={() => handleAddRange(push)}
              >
                <AddIcon style={{ cursor: "pointer" }} />
                <div style={{ cursor: "pointer" }}>
                  <Text className="m__y--8 text--blue">{addtext}</Text>
                </div>
              </Button>
            </div>
          </React.Fragment>
        )}
      </FieldArray>
    </React.Fragment>
  );
};
