/*
 * Copyright OpenSearch Contributors
 * SPDX-License-Identifier: Apache-2.0
 */

import _ from "lodash";
import React, { ChangeEvent, useEffect, useState } from "react";
import {
  EuiCheckbox,
  EuiComboBox,
  EuiDatePicker,
  EuiFieldNumber,
  EuiFieldText,
  EuiFlexGroup,
  EuiFlexItem,
  EuiFormRow,
  EuiLink,
  EuiSelect,
  EuiSpacer,
  EuiText,
} from "@elastic/eui";
import CustomLabel from "../../../../components/CustomLabel";
import { WEEK_DAYS, CRON_SCHEDULE_FREQUENCY_TYPE, TIMEZONES } from "./constants";
import { buildCronExpression, parseCronExpression, startTime } from "./helper";
import moment from "moment-timezone";
import { CRON_EXPRESSION_DOCUMENTATION_URL } from "../../../../utils/constants";

interface CronScheduleProps {
  frequencyType: string;
  onChangeFrequencyType: (e: ChangeEvent<HTMLSelectElement>) => void;
  cronExpression: string;
  onCronExpressionChange: (expression: string) => void;
  showTimezone?: boolean;
  timezone?: string;
  onChangeTimezone?: (timezone: string) => void;
  timezoneError?: string;
  frequencyTitle?: string;
}

const CronSchedule = ({
  frequencyType,
  onChangeFrequencyType,
  cronExpression,
  onCronExpressionChange,
  showTimezone,
  timezone,
  onChangeTimezone,
  timezoneError,
  frequencyTitle = "Schedule frequency",
}: CronScheduleProps) => {
  const { minute: initMin, hour: initHour, dayOfWeek: initWeek, dayOfMonth: initMonth } = parseCronExpression(cronExpression);

  const [minute, setMinute] = useState(initMin);
  const [hour, setHour] = useState(initHour);
  const [dayOfWeek, setWeek] = useState(initWeek);
  const [dayOfMonth, setMonth] = useState(initMonth);

  // When edit policy is clicked, during the initial render DEFAULT values get passed
  // As a result when the actual policy details are passed, the state does not get updated and we end up
  // showing incorrect values in schedule controls.
  if (initHour !== hour) {
    setHour(initHour);
  }

  if (initMin !== minute) {
    setMinute(initMin);
  }

  if (initWeek !== dayOfWeek) {
    setWeek(initWeek);
  }

  if (initMonth !== dayOfMonth) {
    setMonth(initMonth);
  }

  useEffect(() => {
    changeCron();
  }, [minute, hour, dayOfWeek, dayOfMonth]);

  const changeCron = (input?: any) => {
    let cronParts = { hour, minute, dayOfWeek, dayOfMonth, frequencyType };
    cronParts = { ...cronParts, ...input };
    const expression = buildCronExpression(cronParts, cronExpression);
    // console.log(`sm dev built expression ${expression}`);
    onCronExpressionChange(expression);
  };

  function onDayOfWeekChange(dayOfWeek: string) {
    setWeek(dayOfWeek);
    // changeCron({ dayOfWeek });
  }

  function onDayOfMonthChange(dayOfMonth: number) {
    setMonth(dayOfMonth);
    // changeCron({ dayOfMonth });
  }

  function onStartTimeChange(date: moment.Moment) {
    const minute = date.minute();
    const hour = date.hour();
    setMinute(minute);
    setHour(hour);
    // changeCron({ minute, hour });
  }

  function onTypeChange(e: ChangeEvent<HTMLSelectElement>) {
    const frequencyType = e.target.value;
    onChangeFrequencyType(e);
    if (frequencyType === "hourly") setMinute(0);
    changeCron({ frequencyType });
  }

  const dayOfWeekCheckbox = (day: string, checkedDay: string) => (
    <EuiFlexItem key={day} grow={false} style={{ marginRight: "0px" }}>
      <EuiCheckbox id={day} label={day} checked={checkedDay === day} onChange={(e) => onDayOfWeekChange(day)} compressed />
    </EuiFlexItem>
  );

  let startTimeContent;
  startTimeContent = (
    <EuiDatePicker
      showTimeSelect
      showTimeSelectOnly
      selected={startTime(hour, minute)}
      onChange={onStartTimeChange}
      dateFormat="HH:mm"
      timeFormat="HH:mm"
    />
  );
  if (frequencyType === "hourly") {
    startTimeContent = <EuiText size="s">Starts at the beginning of the hour.</EuiText>;
  }

  let additionalContent;
  if (frequencyType === "weekly") {
    // TODO SM if use dayOfWeek not initWeek, somehow it would be SUN
    additionalContent = <EuiFlexGroup>{WEEK_DAYS.map((d) => dayOfWeekCheckbox(d, initWeek))}</EuiFlexGroup>;
  }
  if (frequencyType === "monthly") {
    additionalContent = (
      <>
        <CustomLabel title="On the" />
        <EuiFlexGroup gutterSize="m">
          <EuiFlexItem>
            <EuiSelect options={[{ value: "day", text: "Day" }]} defaultValue="Day" />
          </EuiFlexItem>
          <EuiFlexItem>
            <EuiFieldNumber
              value={dayOfMonth}
              onChange={(e) => {
                onDayOfMonthChange(parseInt(e.target.value));
              }}
              min={1}
              max={31}
            />
          </EuiFlexItem>
        </EuiFlexGroup>
      </>
    );
  }

  const cronExpressionHelpText = (
    <EuiText color="subdued" size="s" style={{ padding: "5px 0px" }}>
      <p style={{ fontWeight: 200, fontSize: "12px" }}>
        Use Cron expression to define complex schedule.{" "}
        <EuiLink href={CRON_EXPRESSION_DOCUMENTATION_URL} target="_blank" rel="noopener noreferrer">
          Learn more
        </EuiLink>
      </p>
    </EuiText>
  );

  return (
    <>
      <CustomLabel title={frequencyTitle} />
      <EuiSelect id="creationCronScheduleType" options={CRON_SCHEDULE_FREQUENCY_TYPE} value={frequencyType} onChange={onTypeChange} />

      <EuiSpacer size="m" />

      <EuiFlexGroup justifyContent="flexStart" alignItems="flexStart">
        <EuiFlexItem style={{ maxWidth: 400 }}>
          {frequencyType === "custom" ? (
            <>
              <CustomLabel title="Cron expression" />
              <EuiFormRow helpText={cronExpressionHelpText}>
                <EuiFieldText
                  value={cronExpression}
                  onChange={(e) => {
                    onCronExpressionChange(e.target.value);
                  }}
                />
              </EuiFormRow>
            </>
          ) : (
            <>
              <CustomLabel title="Start time" />
              {startTimeContent}

              <EuiSpacer size="s" />

              {additionalContent}
            </>
          )}
        </EuiFlexItem>

        {showTimezone ? (
          <EuiFlexItem style={{ maxWidth: 250 }}>
            <CustomLabel title="Time zone" />
            <EuiFormRow isInvalid={!!timezoneError} error={timezoneError}>
              <EuiComboBox
                placeholder="Select a time zone"
                singleSelection={{ asPlainText: true }}
                options={TIMEZONES}
                renderOption={({ label: tz }) => `${tz} (${moment.tz(tz).format("Z")})`}
                selectedOptions={[{ label: timezone ?? "" }]}
                onChange={(options) => {
                  if (onChangeTimezone) {
                    onChangeTimezone(_.first(options)?.label ?? "");
                  }
                }}
              />
            </EuiFormRow>
          </EuiFlexItem>
        ) : null}
      </EuiFlexGroup>
    </>
  );
};

export default CronSchedule;