import React, { useEffect, useRef, useMemo, useState } from 'react';
import {
  Cell,
  DatePicker,
  DatePickerProps,
  FormField,
  Layout,
  TimeInput,
} from '@wix/design-system';
import { BaseInputProps, BaseInputRef } from '../BaseInput';
import { Field } from '../Field';
import { dataHooks } from '../dataHooks';
import { useCustomFieldsFormContext } from '../../components/CustomFieldsFormContext';
import { observer } from 'mobx-react-lite';
import { useWixPatternsContainer } from '@wix/bex-core/react';
import { parse } from 'date-fns';
import { shortDateFormats } from '../../utils/datesUtil';

export interface DateTimeProps extends BaseInputProps<string | null> {}
const _DateTime = ({
  dataHook,
  state,
  schema,
  initialValue,
  inputRef,
  onChange,
}: DateTimeProps) => {
  const {
    environment: { language },
  } = useWixPatternsContainer();
  const rawValue = state._extendedFieldsDataMap.get(schema.id) || initialValue;

  const date = useMemo(() => {
    if (!rawValue) {
      return undefined;
    }
    const d = new Date(rawValue);
    return isNaN(d.getTime()) ? undefined : d;
  }, [rawValue]);
  const [statusMessage, setStatusMessage] = useState('');

  const ref = useRef<BaseInputRef>({});
  const dateRef = useRef<BaseInputRef>({});
  const timeRef = useRef<BaseInputRef>({});
  const [dateValue, setDateValue] = useState<number | string | undefined>(
    date?.getDate(),
  );
  const [timeValue, setTimeValue] = useState<number | string | undefined>(
    date?.getTime(),
  );

  const formState = useCustomFieldsFormContext();

  useEffect(() => {
    ref.current.focus = () => {
      if (dateRef.current.invalid) {
        return dateRef.current.focus?.();
      }

      return timeRef.current.focus?.();
    };

    inputRef?.(ref.current);
  }, []);

  return (
    <Field dataHook={dataHook} type={schema.type}>
      <FormField label={schema.label} dataHook={dataHooks.Label}>
        <Layout>
          <Cell span={6}>
            <DatePicker
              ref={(internalRef) => {
                dateRef.current.focus = () =>
                  // TODO: PR to WSR needed to expose as public API
                  // @ts-expect-error
                  internalRef?.state?.inputRef?.focus?.();
              }}
              width="100%"
              value={date}
              locale={language as DatePickerProps['locale']}
              // onChange is triggered only when you have valid, non-empty value. and onValidate is triggered on every change to we use onValidate
              onChange={() => {}}
              onValidate={({ validationType, value, format }) => {
                if (validationType === 'valid') {
                  const dateWithNewDate = date
                    ? new Date(date)
                    : new Date(value);

                  const _value = parse(
                    value,
                    shortDateFormats[language as keyof typeof shortDateFormats],
                    new Date(),
                  );
                  dateWithNewDate.setFullYear(_value.getFullYear());
                  dateWithNewDate.setMonth(_value.getMonth());
                  dateWithNewDate.setDate(_value.getDate());
                  onChange(dateWithNewDate.toISOString());
                  setDateValue(new Date(value).getDate());
                  setStatusMessage('');
                  dateRef.current.invalid = false;
                } else if (validationType === 'formatError' && value === '') {
                  setStatusMessage('');
                  dateRef.current.invalid = false;
                  setDateValue(value);
                  if (!timeValue) {
                    onChange(null);
                  }
                } else {
                  setStatusMessage(
                    formState._translate(
                      'cairo.customFields.fieldType.date.invalid.value',
                      { dateFormat: format ?? '' },
                    ),
                  );
                  dateRef.current.invalid = true;
                }

                ref.current.invalid =
                  dateRef.current.invalid || timeRef.current.invalid;
              }}
              status={ref.current.invalid ? 'error' : undefined}
              statusMessage={statusMessage}
              dataHook={`${dataHooks.Input}-date`}
            />
          </Cell>
          <Cell span={6}>
            <TimeInput
              ref={(internalRef) => {
                timeRef.current.focus = () => internalRef?.focus();
              }}
              dataHook={`${dataHooks.Input}-time`}
              value={date ?? null}
              invalidMessage={formState._translate(
                'cairo.customFields.fieldType.dateAndTime.invalid.value',
              )}
              onInvalid={() => {
                timeRef.current.invalid = true;
                ref.current.invalid =
                  dateRef.current.invalid || timeRef.current.invalid;
              }}
              onChange={({ date: newValue }) => {
                timeRef.current.invalid = false;
                ref.current.invalid =
                  dateRef.current.invalid || timeRef.current.invalid;

                if (newValue) {
                  const dateWithNewTime = date ? new Date(date) : newValue;
                  dateWithNewTime.setHours(newValue.getHours());
                  dateWithNewTime.setMinutes(newValue.getMinutes());
                  dateWithNewTime.setSeconds(newValue.getSeconds());
                  dateWithNewTime.setMilliseconds(newValue.getMilliseconds());
                  onChange(dateWithNewTime.toISOString());
                } else if (!ref.current.invalid) {
                  if (!newValue) {
                    setTimeValue('');
                    if (!dateValue) {
                      onChange(null);
                    }
                  }
                }
              }}
            />
          </Cell>
        </Layout>
      </FormField>
    </Field>
  );
};

export const DateTime = observer(_DateTime);
