import moment from 'moment';
import { replace, uniq, isEmpty } from 'lodash';
import environment from '~/platform/utilities/environment';
import { apiRequest } from '~/platform/utilities/api';
import {
  getCCTimeZone,
  getVATimeZone,
} from '~/applications/personalization/dashboard-2/utils/timezone';
import {
  FETCH_CONFIRMED_FUTURE_APPOINTMENTS,
  FETCH_CONFIRMED_FUTURE_APPOINTMENTS_FAILED,
  FETCH_CONFIRMED_FUTURE_APPOINTMENTS_SUCCEEDED,
  FUTURE_APPOINTMENTS_HIDDEN_SET,
  VIDEO_TYPES,
} from '~/applications/personalization/dashboard-2/constants';
import MOCK_FACILITIES from '~/applications/personalization/dashboard-2/utils/mocks/appointments/MOCK_FACILITIES.json';
import MOCK_VA_APPOINTMENTS from '~/applications/personalization/dashboard-2/utils/mocks/appointments/MOCK_VA_APPOINTMENTS';
import MOCK_CC_APPOINTMENTS from '~/applications/personalization/dashboard-2/utils/mocks/appointments/MOCK_CC_APPOINTMENTS';

function isAtlasLocation(appointment) {
  return appointment.attributes?.vvsAppointments?.some(
    element => element.tasInfo,
  );
}

function getAdditionalInfo(appointment) {
  const appointmentKind =
    appointment.attributes?.vvsAppointments?.[0]?.appointmentKind;

  if (isAtlasLocation(appointment)) {
    return 'at an ATLAS location';
  }

  if (appointmentKind === VIDEO_TYPES.clinic) {
    return 'at a VA location';
  }

  if (appointmentKind === VIDEO_TYPES.gfe) {
    return 'using a VA device';
  }

  if (
    appointmentKind === VIDEO_TYPES.adhoc ||
    appointmentKind === VIDEO_TYPES.mobile
  ) {
    return 'at home';
  }

  return null;
}

function getStagingID(facilityID) {
  if (!facilityID) {
    return facilityID;
  }

  if (environment.isProduction()) {
    return facilityID;
  }

  if (facilityID.startsWith('983')) {
    return facilityID.replace('983', '442');
  }

  if (facilityID.startsWith('984')) {
    return facilityID.replace('984', '552');
  }

  return facilityID;
}

export function fetchConfirmedFutureAppointments() {
  return async dispatch => {
    dispatch({
      type: FETCH_CONFIRMED_FUTURE_APPOINTMENTS,
    });

    let facilitiesLookup = {};
    let facilitiesResponse;
    let vaAppointments = [];
    let ccAppointments = [];

    const startOfToday = moment()
      .startOf('day')
      .toISOString();

    // Maximum number of days you can schedule an appointment in advance in VAOS
    const endDate = moment()
      .add(395, 'days')
      .startOf('day')
      .toISOString();

    try {
      if (environment.isLocalhost() && !window.Cypress) {
        vaAppointments = MOCK_VA_APPOINTMENTS;
        ccAppointments = MOCK_CC_APPOINTMENTS;
      } else {
        vaAppointments = await apiRequest(
          `/appointments?start_date=${startOfToday}&end_date=${endDate}&type=va`,
          { apiVersion: 'vaos/v0' },
        );
        ccAppointments = await apiRequest(
          `/appointments?start_date=${startOfToday}&end_date=${endDate}&type=cc`,
          { apiVersion: 'vaos/v0' },
        );
      }
      const facilityIDs = uniq(
        vaAppointments.map(
          appointment =>
            getStagingID(appointment?.attributes?.sta6aid)
              ? `vha_${getStagingID(appointment?.attributes?.sta6aid)}`
              : undefined,
        ),
      );

      if (environment.isLocalhost() && !window.Cypress) {
        facilitiesResponse = MOCK_FACILITIES;
      } else {
        facilitiesResponse = await apiRequest(
          `/facilities/va?ids=${facilityIDs.join(',')}`,
          { apiVersion: 'v1' },
        );
      }

      facilitiesLookup = facilitiesResponse?.data?.reduce(
        (lookup, facility) => {
          const facilityID = replace(facility?.id, 'vha_', '');
          // eslint-disable-next-line no-param-reassign
          lookup[facilityID] = facility;
          return lookup;
        },
        {},
      );
    } catch (error) {
      dispatch({
        type: FETCH_CONFIRMED_FUTURE_APPOINTMENTS_FAILED,
      });
    }

    const formattedVAAppointments = vaAppointments.reduce(
      (accumulator, appointment) => {
        const startDate = moment(appointment?.attributes?.startDate);
        const now = moment();
        const appointmentStatus =
          appointment?.attributes?.vdsAppointments?.[0]?.currentStatus;

        // Past appointments should be filtered out already on the api side, this is a safe guard.
        if (startDate.isBefore(now)) {
          return accumulator;
        }

        // Hide cancelled or no-show appointments
        if (FUTURE_APPOINTMENTS_HIDDEN_SET.has(appointmentStatus)) {
          return accumulator;
        }

        // Derive the facility.
        const facility =
          facilitiesLookup[getStagingID(appointment?.attributes?.facilityId)];

        accumulator.push({
          additionalInfo: getAdditionalInfo(appointment),
          facility,
          id: appointment?.id,
          isVideo: !isEmpty(appointment?.attributes?.vvsAppointments),
          providerName: facility?.attributes?.name,
          startsAt: startDate.toISOString(),
          type: 'va',
          timeZone: getVATimeZone(
            getStagingID(appointment?.attributes?.facilityId),
          ),
        });

        return accumulator;
      },
      [],
    );

    const formattedCCAppointments = ccAppointments.reduce(
      (accumulator, appointment) => {
        const startDate = moment(appointment?.attributes?.appointmentTime);
        const now = moment();

        // Escape early if the appointment is in the past.
        if (startDate.isBefore(now)) {
          return accumulator;
        }

        accumulator.push({
          additionalInfo: getAdditionalInfo(appointment),
          id: appointment?.id,
          isVideo: false,
          providerName: appointment?.attributes?.providerPractice,
          startsAt: startDate.toISOString(),
          timeZone: getCCTimeZone(appointment),
          type: 'cc',
        });

        return accumulator;
      },
      [],
    );

    const allAppointments = [
      ...formattedCCAppointments,
      ...formattedVAAppointments,
    ];

    // Sort the appointments by which is soonest.
    const sortedAppointments = allAppointments.sort((a, b) => {
      return moment(a.startsAt).diff(b.startsAt);
    });

    dispatch({
      type: FETCH_CONFIRMED_FUTURE_APPOINTMENTS_SUCCEEDED,
      appointments: sortedAppointments,
    });
  };
}

@@ -2642,32 +2642,38 @@
  else %7B%0A        
+const 
 vaAppointments =
@@ -2662,32 +2662,39 @@
 t vaAppointments
+Reponse
  = await apiRequ
@@ -2828,32 +2828,38 @@
      );%0A        
+const 
 ccAppointments =
@@ -2852,24 +2852,32 @@
 Appointments
+Response
  = await api
@@ -3006,32 +3006,142 @@
 0' %7D,%0A        );
+%0A%0A        vaAppointments = vaAppointmentsReponse?.data;%0A        ccAppointments = ccAppointmentsResponse?.data;
 %0A      %7D%0A      c
@@ -3133,16 +3133,17 @@
       %7D%0A
+%0A
       co

Fix appointments (#16891)