/**
 * List of previous groups that can be selected.
 * @author Benedikt Arnarsson
 */

// Import React
import React, { useReducer, useEffect } from 'react';

// Import FontAwesome
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faPlus } from '@fortawesome/free-solid-svg-icons';

// Import DCE reactkit
import { LoadingSpinner } from '../../../../dce-reactkit';

// Import Grouper
// import { StudentGroupAssignment } from 'dce-live-grouper';

// Import shared types
import CheckInUIProps from '../../../types/CheckInUIProps';
import MMDDYY from '../../../shared/types/MMDDYY';

// Import helpers
import fetchSeriesList from '../helpers/fetchSeriesList';
import SeriesListItem from './SeriesListItem';
import genNewSeriesId from '../helpers/genNewSeriesId';
import parseMMDDYY from '../../../shared/helpers/parseMMDDYY';

/*------------------------------------------------------------------------*/
/* -------------------------------- Types ------------------------------- */
/*------------------------------------------------------------------------*/

// Props definition
type Props = {
  // First part of OccurrenceBasicInfo
  checkInProps: CheckInUIProps,
  // Second part of the OccurrenceBasicInfo
  occurrenceDate: MMDDYY,
  /**
   * Handler for when user has chosen which series to copy from (or chosen to
   *   set up new series)
   * @param opts object containing all arguments
   * @param opts.seriesId the ID of the series to copy from (may be a new
   *   seriesId)
   * @param opts.oldGroups the old groups to copy from (or empty array if
   *   starting a new series)=
   */
  onSelect: (
    opts: (
      | {
        isNewSeries: true,
        seriesId: number,
      }
      | {
        isNewSeries: false,
        seriesId: number,
        mmddyy: MMDDYY,
      }),
  ) => void,
};

// Series map
type SeriesMap = {
  [k: number]: MMDDYY,
};

/*------------------------------------------------------------------------*/
/* -------------------------------- State ------------------------------- */
/*------------------------------------------------------------------------*/

/* -------------- Views ------------- */

enum View {
  // Currently loading the series list
  Loading = 'Loading',
  // Display the series list
  SeriesList = 'SeriesList',
}

/* -------- State Definition -------- */

type State = (
  | {
    // Current view
    view: View.Loading,
  }
  | {
    // Current view
    view: View.SeriesList,
    // Map from seriesId to PreAssignments
    seriesMap: SeriesMap,
    // Largest-to-smallest ordering of series IDs
    seriesIds: number[],
  }
);

/* ------------- Actions ------------ */

// Types of actions
enum ActionType {
  // Transition to View.SeriesList
  DisplaySeriesList = 'DisplaySeriesList',
  // Select a series from the list
  SelectSeries = 'SelectSeries',
}

// Action definitions
type Action = (
  | {
    // Action type
    type: ActionType.DisplaySeriesList,
    // List of previous groups that we will display
    seriesMap: SeriesMap,
  }
);

/**
 * Reducer that executes actions
 * @author Benedikt Arnarsson
 * @param state current state
 * @param action action to execute
 * @returns updated state
 */
const reducer = (state: State, action: Action): State => {
  switch (action.type) {
    case ActionType.DisplaySeriesList: {
      // Get seriesIds
      const { seriesMap } = action;
      const seriesIds = (
        Object
          .keys(seriesMap)
          .map((seriesIdText) => {
            return Number.parseInt(seriesIdText, 10);
          })
      );

      // Sort seriesIds descending (show newest series first)
      seriesIds.sort((a, b) => {
        return b - a;
      });

      // Show series list
      return {
        view: View.SeriesList,
        seriesMap,
        seriesIds,
      };
    }
    default: {
      return state;
    }
  }
};

/*------------------------------------------------------------------------*/
/* ------------------------------ Component ----------------------------- */
/*------------------------------------------------------------------------*/

const SeriesList: React.FC<Props> = (props) => {
  /*------------------------------------------------------------------------*/
  /* -------------------------------- Setup ------------------------------- */
  /*------------------------------------------------------------------------*/

  /* -------------- Props ------------- */

  // Destructure all props
  const {
    checkInProps,
    onSelect,
  } = props;

  /* -------------- State ------------- */

  // Initial state
  const initialState: State = {
    view: View.Loading,
  };

  // Initialize state
  const [state, dispatch] = useReducer(reducer, initialState);

  // Destructure common state
  const {
    view,
  } = state;

  /*------------------------------------------------------------------------*/
  /* ------------------------- Component Functions ------------------------ */
  /*------------------------------------------------------------------------*/

  /*------------------------------------------------------------------------*/
  /* ------------------------- Lifecycle Functions ------------------------ */
  /*------------------------------------------------------------------------*/

  /**
   * Mount: load list of series
   * @author Ben Arnarsson
   * @author Gabe Abrams
   */
  useEffect(
    () => {
      (async () => {
        try {
          // Load series list
          const seriesList = await fetchSeriesList(checkInProps);

          // Convert to map
          const seriesMap: SeriesMap = {};
          seriesList.forEach((seriesInfo) => {
            seriesMap[seriesInfo.seriesId] = parseMMDDYY(seriesInfo.mmddyy);
          });

          // Save to state
          dispatch({
            type: ActionType.DisplaySeriesList,
            seriesMap,
          });
        } catch (err) {
          // TODO: make showFatalError equivalent
          return alert(err);
        }
      })();
    },
    [],
  );

  /*------------------------------------------------------------------------*/
  /* ------------------------------- Render ------------------------------- */
  /*------------------------------------------------------------------------*/

  /*----------------------------------------*/
  /* ---------------- Views --------------- */
  /*----------------------------------------*/

  // Body that will be filled with the current view
  let body: React.ReactNode;

  /* -------- Loading -------- */

  if (view === View.Loading) {
    // Create body
    body = (
      <LoadingSpinner />
    );
  }

  /* ----------- Series List ---------- */

  if (view === View.SeriesList) {
    // Destructure state
    const {
      seriesIds,
      seriesMap,
    } = state;

    // Create body
    body = (
      <div>
        {/* New Groups */}
        <button
          type="button"
          id="DCHUI-SeriesList-new-groups-button"
          className="btn btn-lg alert-success progress-bar-striped btn-block p-3 mb-2"
          style={{ border: '2px dashed black' }}
          aria-label="create a new lounge"
          onClick={() => {
            // Generate new seriesId
            const seriesId = genNewSeriesId(seriesIds);

            // Finish
            onSelect({
              isNewSeries: true,
              seriesId,
            });
          }}
        >
          <h3 className="m-0">
            <FontAwesomeIcon
              icon={faPlus}
              className="mr-2"
            />
            {/* Small Screen View */}
            <span className="d-inline d-sm-none">
              Create
            </span>
            {/* Large Screen View */}
            <span className="d-none d-sm-inline">
              Create New Groups
            </span>
          </h3>
        </button>
        {/* Old Groups */}
        {
          seriesIds.length > 0 &&
            <div>
              {/* <h2>Existing group sets:</h2> */}
              {
                seriesIds.map((seriesId) => {
                  // Render item
                  const mmddyy = seriesMap[seriesId];
                  return (
                    <div className="my-1">
                      <SeriesListItem
                        key={seriesId}
                        displayDate
                        occurrenceDate={mmddyy}
                        onSelect={() => {
                          onSelect({
                            isNewSeries: false,
                            seriesId,
                            mmddyy,
                          });
                        }}
                      />
                    </div>
                  );
                })
              }
            </div>
        }
        
      </div>
    );
  }

  /*----------------------------------------*/
  /* --------------- Main UI -------------- */
  /*----------------------------------------*/

  return (
    <div className="DCHUI-SeriesList-outer-container">
      {body}
    </div>
  );
};

/*------------------------------------------------------------------------*/
/* ------------------------------- Wrap Up ------------------------------ */
/*------------------------------------------------------------------------*/

// Export component
export default SeriesList;
