import {
  INIT_IMAGES,
  INIT_IMAGES_SUCCESS,
  INIT_IMAGES_FAIL,
  NEXT_PAGE,
  NEXT_PAGE_SUCCESS,
  NEXT_PAGE_FAIL,
  GALLERY_ROTATE_PHOTO,
  GALLERY_ROTATE_PHOTO_SUCCESS,
  GALLERY_ROTATE_PHOTO_FAIL,
  rotatePhotoMbdPic,
  rotatePhotoMbdWep,
  getErgImagesHelper
} from '../requests.js';
// import { CounterTableAction as ActionTypes } from '../constants';

export type ImageGalleryState =
  | { tag: 'not_loaded' }
  | { tag: 'loading' }
  | { tag: 'error'; error?: any }
  | {
      tag: 'loaded';
      images: Array<ImageQueryResult>;
      page: number;
      loadingPage: boolean;
      lastPageReached: boolean;
      reloadedImages: {};
    };

export type ImageQueryResult = {
  pic_id: number;
  pic_name: string;
  erg_id: string;
} & (
  | {
      source: 'SOURCE_MBD_PIC';
    }
  | {
      source: 'SOURCE_MBD_WEP';
      pktid: string;
    }
);

// Create a string which uniquely identifies a given ImageQueryResult.
export function uniqueKey(res: ImageQueryResult): string {
  switch (res.source) {
    case 'SOURCE_MBD_WEP':
      return res.source.concat(res.pic_id.toString(), '-', res.pktid);
    case 'SOURCE_MBD_PIC':
      return res.source.concat(res.pic_id.toString());
  }
}

const init: ImageGalleryState = { tag: 'not_loaded' };
const resultsPerPage = 50;

export default function reducer(
  state: ImageGalleryState = init,
  action
): ImageGalleryState {
  switch (action.type) {
    // case ActionTypes.SYNC_COUNTER_TABLE:
    //   const { _page, _pageSize } = action;
    //   return loop(
    //     { ...state, _page, _pageSize },
    //     Cmd.action({ type: GET_COUNTER })
    //   );
    case INIT_IMAGES:
      return { tag: 'loading' };
    case INIT_IMAGES_SUCCESS:
      return {
        tag: 'loaded',
        images: action.data.queryResult,
        page: 0,
        loadingPage: false,
        lastPageReached: action.data.queryResult.length < resultsPerPage,
        reloadedImages: {}
      };
    case INIT_IMAGES_FAIL:
      console.error(action.error);
      return { tag: 'error', error: action.error };
    case NEXT_PAGE:
      return { ...state, loadingPage: true };
    case NEXT_PAGE_SUCCESS:
      if (state.tag === 'loaded') {
        return {
          tag: 'loaded',
          images: [...state.images, ...action.data.queryResult],
          page: state.page + 1,
          loadingPage: false,
          lastPageReached: action.data.queryResult.length < resultsPerPage,
          reloadedImages: state.reloadedImages
        };
      } else {
        console.error(
          'Warning: Received NEXT_PAGE_SUCCESS in non-loaded state.  Ignoring.'
        );
        return state;
      }
    case NEXT_PAGE_FAIL:
      console.error(action.error);
      if (state.tag === 'loaded') {
        return {
          ...state,
          loadingPage: false
        };
      } else {
        console.error(
          'Warning: Received NEXT_PAGE_FAIL in non-loaded state.  Ignoring.'
        );
        return state;
      }
    case GALLERY_ROTATE_PHOTO:
      if (state.tag !== 'loaded') {
        console.error(
          'Warning: Received GALLERY_ROTATE_PHOTO in non-loaded state.  Ignoring'
        );
      }
      return state;
    case GALLERY_ROTATE_PHOTO_SUCCESS:
      if (state.tag !== 'loaded') {
        console.error(
          'Warning: Received GALLERY_ROTATE_PHOTO_SUCCESS in non-loaded state.  Ignoring'
        );
        return state;
      }
      // We will trigger the image to be reloaded by appending the current time to its src URL.
      const cacheKey = uniqueKey(action.queryResult);
      const newReloadedImages = { ...state.reloadedImages, [cacheKey]: new Date().getTime().toString()};
      return {
        ...state,
        reloadedImages: newReloadedImages
      };
    case GALLERY_ROTATE_PHOTO_FAIL:
      console.error(action.error);
      if (state.tag !== 'loaded') {
        console.error(
          'Warning: Received GALLERY_ROTATE_PHOTO_FAIL in non-loaded state.  Ignoring'
        );
        return state;
      }
      return state;
    default:
      return state;
  }
}

const initImagesSuccess = (result) => ({
  type: INIT_IMAGES_SUCCESS,
  data: result.data
});
const initImagesFail = (error) => ({ type: INIT_IMAGES_FAIL, error });

export const initImagesAction = () => async (dispatch, getState) => {
  dispatch({ type: INIT_IMAGES });
  try {
    const result = await getErgImagesHelper(getState, 0, resultsPerPage);
    dispatch(initImagesSuccess(result));
  } catch (err) {
    dispatch(initImagesFail(err));
  }
};

const nextPageSuccess = (result) => ({
  type: NEXT_PAGE_SUCCESS,
  data: result.data
});

const nextPageFail = (error) => ({ type: NEXT_PAGE_FAIL, error });

export const nextPageAction = () => async (dispatch, getState) => {
  dispatch({ type: NEXT_PAGE });
  const { page } = getState().imageGallery;
  try {
    const result = await getErgImagesHelper(getState, page + 1, resultsPerPage);
    dispatch(nextPageSuccess(result));
  } catch (err) {
    dispatch(nextPageFail(err));
  }
};

const galleryRotatePhotoSuccess = (queryResult: ImageQueryResult) => ({
  type: GALLERY_ROTATE_PHOTO_SUCCESS as string,
  queryResult
});
const galleryRotatePhotoFail = (error) => ({
  type: GALLERY_ROTATE_PHOTO_FAIL,
  error
});
export const galleryRotatePhoto = (queryResult: ImageQueryResult) => async (dispatch) => {
  dispatch({ type: GALLERY_ROTATE_PHOTO });
  let rotatePhotoRoute;
  let routeArgs;
  switch (queryResult.source) {
    case 'SOURCE_MBD_PIC':
      rotatePhotoRoute = rotatePhotoMbdPic;
      routeArgs = [queryResult.pic_id];
      break;
    case 'SOURCE_MBD_WEP':
      rotatePhotoRoute = rotatePhotoMbdWep;
      routeArgs = [queryResult.pic_name];
      break;
  }
  try {
    const result = await rotatePhotoRoute(routeArgs);
    dispatch(galleryRotatePhotoSuccess(result.data));
  } catch (err) {
    dispatch(galleryRotatePhotoFail(err));
  }
};
