import React, { useCallback, useEffect, useRef, useState } from 'react';
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import { Controller, useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import {
  Button,
  ButtonSet,
  Form,
  InlineLoading,
  NumberInput,
  Select,
  SelectItem,
  Stack,
  TextArea,
  TimePicker,
  TimePickerSelect,
  Search,
} from '@carbon/react';
import { zodResolver } from '@hookform/resolvers/zod';
import {
  ExtensionSlot,
  OpenmrsDatePicker,
  ResponsiveWrapper,
  showSnackbar,
  translateFrom,
  useConfig,
  useLayoutType,
  useLocations,
  usePatient,
  useSession,
  type DefaultWorkspaceProps,
} from '@openmrs/esm-framework';
import { z } from 'zod';
import { type ConfigObject } from '../config-schema';
import {
  saveAppointment,
  useAppointmentService,
  useMutateAppointments,
  useAppointments,
  editAppointment,
} from './appointments-form.resource';
import { dateFormat, moduleName } from '../constants';
import { useProviders } from '../hooks/useProviders';
import type { Appointment, RecurringPattern } from '../types';
import { useSelectedDateContext } from '../hooks/selected-date-context';
import styles from './appointments-form.scss';
import { useConceptAnswers } from '../hooks/useConceptAnswers';
import { useSearchableLocations } from '../hooks/useSearchableLocations';

// Enable dayjs UTC plugin for timezone handling
dayjs.extend(utc);

interface AppointmentsFormProps {
  appointment?: Appointment;
  recurringPattern?: RecurringPattern;
  patientUuid?: string;
  context: string;
}

const AppointmentsForm: React.FC<AppointmentsFormProps & DefaultWorkspaceProps> = ({
  appointment,
  patientUuid,
  context,
  closeWorkspace,
  promptBeforeClosing,
}) => {
  const { patient } = usePatient(patientUuid);
  const { mutateAppointments } = useMutateAppointments();
  const appointmentDateTime = appointment?.startDateTime || appointment?.appointmentDate;
  const editedAppointmentTimeFormat = appointmentDateTime
    ? new Date(appointmentDateTime).getHours() >= 12
      ? 'PM'
      : 'AM'
    : new Date().getHours() >= 12
    ? 'PM'
    : 'AM';
  const defaultTimeFormat = appointmentDateTime
    ? editedAppointmentTimeFormat
    : new Date().getHours() >= 12
    ? 'PM'
    : 'AM';

  const [searchTerm, setSearchTerm] = useState(appointment?.location?.name || '');
  const [debouncedSearchTerm, setDebouncedSearchTerm] = useState(appointment?.location?.name || '');
  const searchInputRef = useRef(null);
  const { t } = useTranslation();
  const isTablet = useLayoutType() === 'tablet';
  const locations = useLocations(null); // Get all locations for creating appointments
  const searchableLocations = useSearchableLocations(debouncedSearchTerm); // Get filtered locations for search
  const providers = useProviders();
  const session = useSession();
  const { selectedDate } = useSelectedDateContext();
  const { data: servicesRaw, isLoading } = useAppointmentService();
  const services = servicesRaw || [];
  const { appointmentReasonConceptUuid } = useConfig<ConfigObject>();
  const { answers: reasonOptions, isLoading: isLoadingReasons } = useConceptAnswers(appointmentReasonConceptUuid);
  const appointmentsAbortController = new AbortController();
  const { data: appointmentsData, mutate: mutatePatientAppointments } = useAppointments(
    patientUuid,
    dayjs(selectedDate).format('YYYY-MM-DDTHH:mm:ss.SSSZZ'),
    appointmentsAbortController,
  );
  const [isSuccessful, setIsSuccessful] = useState(false);
  const [isSubmitting, setIsSubmitting] = useState(false);

  useEffect(() => {
    const timeoutId = setTimeout(() => {
      setDebouncedSearchTerm(searchTerm);
    }, 300);
    return () => clearTimeout(timeoutId);
  }, [searchTerm]);

  const defaultStartDate = appointmentDateTime
    ? new Date(appointmentDateTime)
    : selectedDate
    ? new Date(selectedDate)
    : new Date();
  const defaultStartDateText = appointmentDateTime
    ? dayjs(new Date(appointmentDateTime)).format(dateFormat)
    : selectedDate
    ? dayjs(selectedDate).format(dateFormat)
    : dayjs(new Date()).format(dateFormat);

  const defaultAppointmentStartTime = appointmentDateTime
    ? dayjs(new Date(appointmentDateTime)).format('hh:mm')
    : dayjs(new Date()).format('hh:mm');

  const appointmentsFormSchema = z
    .object({
      location: z.string().refine((value) => value !== '', {
        message: translateFrom(moduleName, 'locationRequired', 'Location is required'),
      }),
      selectedService: z.string().refine((value) => value !== '', {
        message: translateFrom(moduleName, 'serviceRequired', 'Service is required'),
      }),
      provider: z.string().refine((value) => value !== '', {
        message: translateFrom(moduleName, 'providerRequired', 'Provider is required'),
      }),
      reason: z.string().refine((value) => value !== '', {
        message: translateFrom(moduleName, 'reasonRequired', 'Reason is required'),
      }),
      appointmentDateTime: z.object({
        startDate: z.date(),
        startDateText: z.string(),
      }),
      startTime: z.string().regex(/^(1[0-2]|0?[1-9]):[0-5][0-9]$/, 'Invalid time format'),
      timeFormat: z.enum(['AM', 'PM']),
      appointmentNote: z.string().optional(),
      nextVisitDate: z.string().optional(),
    })
    .superRefine((val, ctx) => {
      try {
        const [hours12Str, minutesStr] = (val.startTime || '').split(':');
        const hours12 = Number(hours12Str);
        const minutes = Number(minutesStr);
        if (Number.isNaN(hours12) || Number.isNaN(minutes)) {
          return;
        }
        let hours24 = hours12;
        if (val.timeFormat === 'PM' && hours12 !== 12) {
          hours24 = hours12 + 12;
        } else if (val.timeFormat === 'AM' && hours12 === 12) {
          hours24 = 0;
        }
        const candidate = dayjs(val.appointmentDateTime.startDate)
          .hour(hours24)
          .minute(minutes)
          .second(0)
          .millisecond(0);

        if (candidate.isBefore(dayjs())) {
          ctx.addIssue({
            code: z.ZodIssueCode.custom,
            path: ['appointmentDateTime', 'startDate'],
            message: translateFrom(
              moduleName,
              'appointmentMustBeFuture',
              'Appointment date & time must be in the future',
            ),
          });
        }
      } catch {
        // no-op; other validators will surface errors
      }
    });

  type AppointmentFormData = z.infer<typeof appointmentsFormSchema>;

  const {
    control,
    getValues,
    setValue,
    watch,
    handleSubmit,
    reset,
    formState: { errors, isDirty },
  } = useForm<AppointmentFormData>({
    mode: 'all',
    resolver: zodResolver(appointmentsFormSchema),
    defaultValues: {
      location: appointment?.location?.uuid ?? session?.sessionLocation?.uuid ?? '',
      selectedService:
        appointment?.service?.serviceId?.toString() || appointment?.appointmentService?.serviceId?.toString() || '',
      reason: appointment?.reason?.value?.uuid || '',
      startTime: defaultAppointmentStartTime,
      timeFormat: defaultTimeFormat, // Added default timeFormat
      appointmentDateTime: {
        startDate: defaultStartDate,
        startDateText: defaultStartDateText,
      },
      appointmentNote: appointment?.note || '',
      provider: appointment?.provider?.uuid || '',
    },
  });

  useEffect(() => {
    if (isSuccessful) {
      reset();
      promptBeforeClosing(() => false);
      if (typeof closeWorkspace === 'function') {
        closeWorkspace();
      }
      return;
    }
    promptBeforeClosing(() => isDirty);
  }, [isDirty, promptBeforeClosing, isSuccessful, reset, closeWorkspace]);

  useEffect(() => {
    if (appointment && context === 'editing') {
      if (appointment.location?.uuid) {
        setValue('location', appointment.location.uuid);
        if (appointment.location?.name) {
          setSearchTerm(appointment.location.display);
        }
      }

      if (appointment.service?.serviceId || appointment.appointmentService?.serviceId) {
        const serviceId = appointment.service?.serviceId || appointment.appointmentService?.serviceId;
        setValue('selectedService', serviceId.toString());
      }

      if (appointment.reason?.value?.uuid) {
        setValue('reason', appointment.reason.value.uuid);
      }

      if (appointment.provider?.uuid) {
        setValue('provider', appointment.provider.uuid);
      }

      if (appointment.note) {
        setValue('appointmentNote', appointment.note);
      }

      // Handle appointment date and time
      const appointmentDateTimeValue = appointment.startDateTime || appointment.appointmentDate;
      if (appointmentDateTimeValue) {
        const appointmentDate = new Date(appointmentDateTimeValue);
        setValue('appointmentDateTime', {
          startDate: appointmentDate,
          startDateText: dayjs(appointmentDate).format(dateFormat),
        });

        // Set time fields
        const timeString = dayjs(appointmentDate).format('hh:mm');
        const timeFormat = appointmentDate.getHours() >= 12 ? 'PM' : 'AM';
        setValue('startTime', timeString);
        setValue('timeFormat', timeFormat);
      }
    }
  }, [appointment, context, setValue]);

  const handleSaveAppointment = async (data: AppointmentFormData) => {
    setIsSubmitting(true);

    const serviceObj = services?.find((service) => String(service.serviceId) === String(data.selectedService));
    if (!serviceObj) {
      setIsSubmitting(false);
      showSnackbar({
        isLowContrast: true,
        kind: 'error',
        title: t('serviceRequired', 'Service is required'),
      });
      return;
    }

    const createAppointmentDateTime = (formData: AppointmentFormData): string => {
      // Convert 12-hour time to 24-hour format
      const [hours12, minutes] = formData.startTime.split(':').map(Number);
      let hours24 = hours12;
      if (formData.timeFormat === 'PM' && hours12 !== 12) {
        hours24 = hours12 + 12;
      } else if (formData.timeFormat === 'AM' && hours12 === 12) {
        hours24 = 0;
      }

      const appointmentDateTime = dayjs(formData.appointmentDateTime.startDate)
        .hour(hours24)
        .minute(minutes)
        .second(0)
        .millisecond(0);

      return appointmentDateTime.format('YYYY-MM-DDTHH:mm:ss.SSS');
    };

    const appointmentDate = createAppointmentDateTime(data);

    const payload = {
      appointmentDate,
      reason: {
        person: patientUuid,
        concept: appointmentReasonConceptUuid,
        value: data.reason,
        obsDatetime: appointmentDate,
      },
      nextVisitDate: data.nextVisitDate || undefined,
      note: data.appointmentNote,
      encounter: null,
      location: data.location,
      provider: data.provider,
      service: { serviceId: serviceObj.serviceId },
      patient: patientUuid,
    };

    // Frontend conflict check: same patient, exact time match
    const existingAppointments = appointmentsData?.upcomingAppointments || [];
    const hasConflict = existingAppointments.some((existing) => {
      // Compare the appointment times for exact match
      const existingDateTime = existing.appointmentDate || existing.startDateTime;

      // Normalize both times to the same format for comparison
      const existingTime = dayjs(existingDateTime).format('YYYY-MM-DDTHH:mm:ss');
      const newTime = dayjs(appointmentDate).format('YYYY-MM-DDTHH:mm:ss');

      return existingTime === newTime;
    });

    if (hasConflict) {
      setIsSubmitting(false);
      showSnackbar({
        isLowContrast: true,
        kind: 'error',
        title: t('patientDoubleBooking', 'Patient already booked for an appointment at this time'),
      });
      return;
    }

    const abortController = new AbortController();

    try {
      // Create optimistic appointment object for immediate UI update
      const newAppointment = {
        uuid: `temp-${Date.now()}`,
        startDateTime: appointmentDate,
        endDateTime: appointmentDate,
        appointmentDate: appointmentDate,
        status: 'Scheduled',
        service: {
          name: serviceObj.name,
          serviceId: serviceObj.serviceId,
        },
        location: {
          uuid: data.location,
          display: locations?.find((loc) => loc.uuid === data.location)?.display || data.location,
          name: locations?.find((loc) => loc.uuid === data.location)?.display || data.location,
        },
        provider: {
          uuid: data.provider,
          display: providers?.providers?.find((p) => p.uuid === data.provider)?.display || data.provider,
        },
        reason: {
          person: patientUuid,
          concept: appointmentReasonConceptUuid,
          value: data.reason,
          obsDatetime: appointmentDate,
        },
        note: data.appointmentNote,
        comments: data.appointmentNote,
        patient: {
          uuid: patientUuid,
        },
      };

      // Optimistically update the appointments cache
      if (appointmentsData) {
        mutatePatientAppointments((currentData) => {
          if (!currentData) {
            return currentData;
          }

          const currentResults = (currentData as any)?.data?.results || [];
          const updatedResults = [...currentResults, newAppointment];

          return {
            ...currentData,
            data: {
              ...(currentData as any).data,
              results: updatedResults,
            },
          };
        }, false);
      }

      const response = appointment?.appointmentId
        ? await editAppointment(String(appointment.appointmentId), payload, abortController)
        : await saveAppointment(payload, abortController);

      if (response.status === 200 || response.status === 201) {
        setIsSubmitting(false);
        setIsSuccessful(true);

        // Revalidate all appointment-related queries
        mutatePatientAppointments();
        mutateAppointments();

        showSnackbar({
          isLowContrast: true,
          kind: 'success',
          subtitle: t('appointmentNowVisible', 'It is now visible on the Appointments page'),
          title:
            context === 'editing'
              ? t('appointmentEdited', 'Appointment edited')
              : t('appointmentScheduled', 'Appointment scheduled'),
        });
      } else if (response.status === 204) {
        setIsSubmitting(false);
        mutatePatientAppointments();
        mutateAppointments();

        showSnackbar({
          title:
            context === 'editing'
              ? t('appointmentEditError', 'Error editing appointment')
              : t('appointmentFormError', 'Error scheduling appointment'),
          kind: 'error',
          isLowContrast: false,
          subtitle: t('noContent', 'No Content'),
        });
      } else {
        setIsSubmitting(false);
        mutatePatientAppointments();

        showSnackbar({
          title:
            context === 'editing'
              ? t('appointmentEditError', 'Error editing appointment')
              : t('appointmentFormError', 'Error scheduling appointment'),
          kind: 'error',
          isLowContrast: false,
          subtitle: `Unexpected response status: ${response.status}`,
        });
      }
    } catch (error) {
      setIsSubmitting(false);
      mutatePatientAppointments();

      showSnackbar({
        title:
          context === 'editing'
            ? t('appointmentEditError', 'Error editing appointment')
            : t('appointmentFormError', 'Error scheduling appointment'),
        kind: 'error',
        isLowContrast: false,
        subtitle: error?.message || 'An unexpected error occurred',
      });
    }
  };

  const handleSearchTermChange = useCallback(
    (event: React.ChangeEvent<HTMLInputElement>) => {
      const newSearchTerm = event.target.value ?? '';
      setSearchTerm(newSearchTerm);
    },
    [setSearchTerm],
  );

  if (isLoading) {
    return (
      <InlineLoading className={styles.loader} description={`${t('loading', 'Loading')} ...`} role="progressbar" />
    );
  }
  return (
    <Form onSubmit={handleSubmit(handleSaveAppointment)}>
      <Stack gap={4}>
        {patient && (
          <ExtensionSlot
            name="patient-header-slot"
            state={{
              patient,
              patientUuid: patientUuid,
              hideActionsOverflow: true,
            }}
          />
        )}
        <section className={styles.formGroup}>
          <span className={styles.heading}>{t('location', 'Location')}</span>
          <ResponsiveWrapper>
            {appointment ? (
              // Show search input when editing an appointment
              <>
                <div style={{ marginBottom: '1rem' }}>
                  <Search
                    size="lg"
                    placeholder={t('searchLocation', 'Search for a location')}
                    labelText={t('searchLocation', 'Search location')}
                    onChange={handleSearchTermChange}
                    ref={searchInputRef}
                    value={searchTerm}
                  />
                  {searchTerm && debouncedSearchTerm !== searchTerm && (
                    <div style={{ marginTop: '0.5rem', fontSize: '0.875rem', color: '#6f6f6f' }}>
                      {t('searching', 'Searching...')}
                    </div>
                  )}
                  {searchTerm && debouncedSearchTerm === searchTerm && searchableLocations.locations?.length === 0 && (
                    <div style={{ marginTop: '0.5rem', fontSize: '0.875rem', color: '#da1e28' }}>
                      {t('noLocationsFound', 'No locations found matching your search')}
                    </div>
                  )}
                  {searchTerm &&
                    debouncedSearchTerm === searchTerm &&
                    searchableLocations.locations?.length > 0 &&
                    !locations?.find((loc) => loc.uuid === watch('location'))?.display?.includes(searchTerm) && (
                      <div style={{ marginTop: '0.5rem' }}>
                        <div style={{ fontSize: '0.875rem', color: '#0f62fe', marginBottom: '0.5rem' }}>
                          {t('searchResults', 'Search results:')}
                        </div>
                        <div
                          style={{
                            maxHeight: '200px',
                            overflowY: 'auto',
                            border: '1px solid #e0e0e0',
                            borderRadius: '4px',
                            backgroundColor: '#f4f4f4',
                          }}
                        >
                          {searchableLocations.locations.map((location) => (
                            <div
                              key={location.uuid}
                              role="button"
                              tabIndex={0}
                              onClick={() => {
                                setValue('location', location.uuid);
                                setSearchTerm(location.display); // Show selected location name in search input
                              }}
                              onKeyDown={(e) => {
                                if (e.key === 'Enter' || e.key === ' ') {
                                  setValue('location', location.uuid);
                                  setSearchTerm(location.display);
                                }
                              }}
                              style={{
                                padding: '0.75rem',
                                cursor: 'pointer',
                                borderBottom: '1px solid #e0e0e0',
                                backgroundColor: 'white',
                                transition: 'background-color 0.2s',
                                outline: 'none',
                              }}
                              onMouseEnter={(e) => (e.currentTarget.style.backgroundColor = '#f0f8ff')}
                              onMouseLeave={(e) => (e.currentTarget.style.backgroundColor = 'white')}
                            >
                              <div style={{ fontWeight: '500', fontSize: '0.875rem' }}>{location.display}</div>
                              {location.description && (
                                <div style={{ fontSize: '0.75rem', color: '#6f6f6f', marginTop: '0.25rem' }}>
                                  {location.description}
                                </div>
                              )}
                            </div>
                          ))}
                        </div>
                      </div>
                    )}
                </div>
              </>
            ) : (
              // Show only dropdown when creating a new appointment
              <Controller
                name="location"
                control={control}
                render={({ field: { onChange, value, onBlur, ref } }) => (
                  <Select
                    id="location"
                    invalid={!!errors?.location}
                    invalidText={errors?.location?.message}
                    labelText={t('selectALocation', 'Select a location')}
                    onChange={onChange}
                    onBlur={onBlur}
                    ref={ref}
                    value={value}
                  >
                    <SelectItem text={t('chooseLocation', 'Choose a location')} value="" />
                    {locations?.length > 0 &&
                      locations
                        .filter((location) => location && location.uuid)
                        .map((location) => (
                          <SelectItem key={location.uuid} text={location.display} value={location.uuid}>
                            {location.display}
                          </SelectItem>
                        ))}
                  </Select>
                )}
              />
            )}
          </ResponsiveWrapper>
        </section>
        <section className={styles.formGroup}>
          <span className={styles.heading}>{t('service', 'Service')}</span>
          <ResponsiveWrapper>
            <Controller
              name="selectedService"
              control={control}
              render={({ field: { onBlur, onChange, value, ref } }) => (
                <Select
                  id="service"
                  invalid={!!errors?.selectedService}
                  invalidText={errors?.selectedService?.message}
                  labelText={t('selectService', 'Select a service')}
                  onBlur={onBlur}
                  onChange={onChange}
                  ref={ref}
                  value={value}
                >
                  <SelectItem text={t('chooseService', 'Select service')} value="" />
                  {services.length > 0 &&
                    services
                      .filter((service) => service && service.serviceId)
                      .map((service) => (
                        <SelectItem key={service.serviceId} text={service.name} value={service.serviceId}>
                          {service.name}
                        </SelectItem>
                      ))}
                </Select>
              )}
            />
          </ResponsiveWrapper>
        </section>
        <section className={styles.formGroup}>
          <span className={styles.heading}>{t('reason', 'Reason')}</span>
          <ResponsiveWrapper>
            <Controller
              name="reason"
              control={control}
              render={({ field: { onChange, value, onBlur, ref } }) => (
                <Select
                  id="reason"
                  invalid={!!errors?.reason}
                  invalidText={errors?.reason?.message}
                  labelText={t('selectReason', 'Select a reason for the appointment')}
                  onChange={onChange}
                  onBlur={onBlur}
                  ref={ref}
                  value={value}
                >
                  <SelectItem text={t('chooseReason', 'Choose a reason')} value="" />
                  {reasonOptions?.length > 0 &&
                    reasonOptions
                      .filter((answer) => answer && answer.uuid)
                      .map((answer) => (
                        <SelectItem key={answer.uuid} text={answer.display} value={answer.uuid}>
                          {answer.display}
                        </SelectItem>
                      ))}
                </Select>
              )}
            />
          </ResponsiveWrapper>
        </section>
        <section className={styles.formGroup}>
          <span className={styles.heading}>{t('dateTime', 'Date & Time')}</span>
          <ResponsiveWrapper>
            <Controller
              name="appointmentDateTime"
              control={control}
              render={({ field, fieldState }) => (
                <OpenmrsDatePicker
                  {...field}
                  value={field.value.startDate}
                  onChange={(date) => {
                    field.onChange({
                      ...field.value,
                      startDate: date,
                    });
                  }}
                  id="datePickerInput"
                  data-testid="datePickerInput"
                  labelText={t('date', 'Date')}
                  style={{ width: '100%' }}
                  invalid={Boolean(fieldState?.error?.message)}
                  invalidText={fieldState?.error?.message}
                  minDate={dayjs().startOf('day').toDate()}
                />
              )}
            />
          </ResponsiveWrapper>
          <ResponsiveWrapper>
            <Controller
              name="startTime"
              control={control}
              render={({ field: { onChange, value } }) => (
                <TimePicker
                  id="time-picker"
                  labelText={t('time', 'Time')}
                  pattern="^(1[0-2]|0?[1-9]):[0-5][0-9]$"
                  onChange={(event) => onChange(event.target.value.replace(/\s/g, ''))}
                  value={value}
                  invalid={!!errors?.startTime}
                  invalidText={errors?.startTime?.message}
                >
                  <Controller
                    name="timeFormat"
                    control={control}
                    render={({ field: { value: timeFormatValue, onChange: timeFormatOnChange } }) => (
                      <TimePickerSelect
                        id="time-picker-select"
                        onChange={(event) => timeFormatOnChange(event.target.value as 'AM' | 'PM')}
                        value={timeFormatValue}
                        aria-label={t('timeFormat', 'Time Format')}
                      >
                        <SelectItem value="AM" text="AM" />
                        <SelectItem value="PM" text="PM" />
                      </TimePickerSelect>
                    )}
                  />
                </TimePicker>
              )}
            />
          </ResponsiveWrapper>
        </section>
        <section className={styles.formGroup}>
          <span className={styles.heading}>{t('note', 'Note')}</span>
          <ResponsiveWrapper>
            <Controller
              name="appointmentNote"
              control={control}
              render={({ field: { onChange, onBlur, value, ref } }) => (
                <TextArea
                  id="appointmentNote"
                  value={value}
                  labelText={t('appointmentNoteLabel', 'Write an additional note')}
                  placeholder={t('appointmentNotePlaceholder', 'Write any additional points here')}
                  onChange={onChange}
                  onBlur={onBlur}
                  ref={ref}
                />
              )}
            />
          </ResponsiveWrapper>
        </section>
        <section className={styles.formGroup}>
          <span className={styles.heading}>{t('provider', 'Provider')}</span>
          <ResponsiveWrapper>
            <Controller
              name="provider"
              control={control}
              render={({ field: { onChange, value, onBlur, ref } }) => (
                <Select
                  id="provider"
                  invalid={!!errors?.provider}
                  invalidText={errors?.provider?.message}
                  labelText={t('selectProvider', 'Select a provider')}
                  onChange={onChange}
                  onBlur={onBlur}
                  value={value}
                  ref={ref}
                >
                  <SelectItem text={t('chooseProvider', 'Choose a provider')} value="" />
                  {providers?.providers?.length > 0 &&
                    providers.providers
                      .filter((provider) => provider && provider.uuid)
                      .map((provider) => (
                        <SelectItem key={provider.uuid} text={provider.display} value={provider.uuid}>
                          {provider.display}
                        </SelectItem>
                      ))}
                </Select>
              )}
            />
          </ResponsiveWrapper>
        </section>
      </Stack>
      <ButtonSet className={isTablet ? styles.tablet : styles.desktop}>
        <Button className={styles.button} onClick={closeWorkspace} kind="secondary">
          {t('discard', 'Discard')}
        </Button>
        <Button className={styles.button} disabled={isSubmitting} type="submit">
          {t('saveAndClose', 'Save and close')}
        </Button>
      </ButtonSet>
    </Form>
  );
};

function TimeAndDuration({ t, watch, control, services, errors }) {
  const defaultDuration = services?.find((service) => service.name === watch('selectedService'))?.durationMins || null;

  return (
    <>
      <ResponsiveWrapper>
        <Controller
          name="startTime"
          control={control}
          render={({ field: { onChange, value } }) => (
            <TimePicker
              id="time-picker"
              labelText={t('time', 'Time')}
              pattern="^([01]\\d|2[0-3]):([0-5]\\d)$"
              onChange={(event) => onChange(event.target.value)}
              value={value}
            />
          )}
        />
      </ResponsiveWrapper>
      <ResponsiveWrapper>
        <Controller
          name="duration"
          control={control}
          render={({ field: { onChange, onBlur, value, ref } }) => (
            <NumberInput
              disableWheel
              hideSteppers
              id="duration"
              invalid={!!errors?.duration}
              invalidText={errors?.duration?.message}
              label={t('durationInMinutes', 'Duration (minutes)')}
              max={1440}
              min={0}
              onBlur={onBlur}
              onChange={(event) => onChange(event.target.value === '' ? null : Number(event.target.value))}
              ref={ref}
              size="md"
              value={value}
            />
          )}
        />
      </ResponsiveWrapper>
    </>
  );
}

export default AppointmentsForm;
