import "./AvailabilityCalendar.scss";
import React from "react";
import { useState } from "react";
import { Button } from "antd";
import { Icon } from "components/Icon";
import classNames from "classnames";
import { Text } from "components/Typography";
import { Col, Row } from "antd/lib/grid";
import chunk from "lodash/chunk";
import { useEffect } from "react";
import moment from "moment";
import { isSameDay } from "utils/date";
import { DATE_FORTMAT } from "utils/available-periods";

interface Props {
  className?: string;
  selected?: moment.Moment[];
  dayHasAvailablePeriods?: string[];
  formatDay?: string;
  selectedTimezone?: string;
  onDayClickCallback?: (day: moment.Moment) => void;
  onChangeContextCallback?: (value: moment.Moment) => void;
}

const AvailabilityCalendar: React.FC<Props> = ({
  className,
  selected,
  dayHasAvailablePeriods,
  formatDay = DATE_FORTMAT,
  onDayClickCallback,
  onChangeContextCallback,
}) => {
  const [dateContext, setDateContext] = useState<moment.Moment>(moment());
  const [showMonthPopup, setShowMonthPopup] = useState(false);

  const weekdaysShort = moment.weekdaysShort(); // ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
  const months = moment.months();

  useEffect(() => {
    onChangeContextCallback && onChangeContextCallback(dateContext);
  }, [dateContext]);

  useEffect(() => {
    if (
      selected?.[0] &&
      moment(selected?.[0]).clone().isSameOrAfter(moment())
    ) {
      setDateContext(moment(selected?.[0]).clone());
    }
  }, [selected]);

  const firstDayOfMonth = () => {
    const firstDay = moment(dateContext).startOf("month").format("d"); // Day of week 0...1..5...6
    return Number(firstDay);
  };

  const numberDaysInMonth = () => {
    return dateContext.daysInMonth();
  };

  const currentYear = () => {
    return dateContext.format("Y");
  };

  const currentMonth = () => {
    return dateContext.format("MMMM");
  };

  const onDayClick = (day: number) => {
    const date = moment(dateContext).startOf("day").date(day);
    onDayClickCallback && onDayClickCallback(date);
  };

  const nextMonth = () => {
    const dateContextPrev = moment(dateContext.clone()).add(1, "month");
    setDateContext(dateContextPrev);
  };

  const prevMonth = () => {
    const dateContextPrev = moment(dateContext.clone()).subtract(1, "month");
    setDateContext(dateContextPrev);
  };

  const setMonth = (month: string) => {
    const monthNo = months.indexOf(month);
    const dateContextNew = moment(dateContext.clone()).set("month", monthNo);
    setDateContext(dateContextNew);
    setShowMonthPopup(false);
  };

  const nextYear = () => {
    const dateContextPrev = moment(dateContext.clone()).add(1, "year");
    setDateContext(dateContextPrev);
  };

  const prevYear = () => {
    const dateContextPrev = moment(dateContext.clone()).subtract(1, "year");
    setDateContext(dateContextPrev);
  };

  const SelectMonthList = () => {
    return (
      <React.Fragment>
        <Row>
          {months.map((data) => (
            <Col
              className="month-slot"
              key={data}
              onClick={() => setMonth(data)}
              span={8}
            >
              <Text>{data}</Text>
            </Col>
          ))}
        </Row>
      </React.Fragment>
    );
  };

  const blanks = [];
  for (let i = 0; i < firstDayOfMonth(); i++) {
    blanks.push(
      <td key={i * 80} className="empty-slot">
        {""}
      </td>
    );
  }

  const daysInMonth = [];
  for (let d = 1; d <= numberDaysInMonth(); d++) {
    const date = dateContext.startOf("day").date(d);
    const isPass = moment().startOf("day").isAfter(date);
    const isCurrentDay = isSameDay(date, moment());
    const isDisabledDay = isPass && !isCurrentDay;
    const isHasAvailablePeriods = dayHasAvailablePeriods?.includes(
      date.clone().format(formatDay)
    );

    const className = classNames({
      day: true,
      "day-has-availability": isHasAvailablePeriods,
      "current-day": isCurrentDay,
      "selected-day": selected?.find((d) => isSameDay(d, date)),
      "disabled-day": isDisabledDay,
    });

    daysInMonth.push(
      <td key={d} className={className}>
        <div className="day-content">
          <div
            className="day-content__title"
            onClick={() => !isDisabledDay && onDayClick(d)}
          >
            <Text>{d}</Text>
          </div>
          {isHasAvailablePeriods && <div className="day-content__dot"></div>}
        </div>
      </td>
    );
  }

  const totalSlots = [...blanks, ...daysInMonth];
  const rows: JSX.Element[][] = chunk(totalSlots, 7);

  const trElems = rows.map((d, i) => {
    if (!d.length) return null;
    return <tr key={i * 100}>{d}</tr>;
  });

  const Weekdays = weekdaysShort.map((day) => {
    return (
      <td key={day} className="week-day">
        <Text preset="medium14" className="text__transform--uppercase">
          {day}
        </Text>
      </td>
    );
  });

  return (
    <React.Fragment>
      <div className={classNames("calendar-container", className)}>
        <div className="calendar-container__header">
          <div>
            <Button
              type="text"
              onClick={() => setShowMonthPopup((preState) => !preState)}
            >
              <Text
                preset="semibold18"
                className="label-month"
              >{`${currentMonth()} ${currentYear()}`}</Text>
            </Button>
          </div>
          <div>
            <Button
              type="text"
              onClick={() => (showMonthPopup ? prevYear() : prevMonth())}
            >
              <Icon name="arrow-left" />
            </Button>
            <Button
              type="text"
              onClick={() => (showMonthPopup ? nextYear() : nextMonth())}
            >
              <Icon name="arrow-right" />
            </Button>
          </div>
        </div>
        <table className="calendar-container__table">
          <tbody>
            {showMonthPopup ? (
              <SelectMonthList />
            ) : (
              <React.Fragment>
                <tr>{Weekdays}</tr>
                {trElems}
              </React.Fragment>
            )}
          </tbody>
        </table>
      </div>
    </React.Fragment>
  );
};

export default React.memo(AvailabilityCalendar);
