import { IBookmark } from "@lonelyplanet/open-planet-node/dist/resources/bookmark";
import { IBookmarkList } from "@lonelyplanet/open-planet-node/dist/resources/bookmarkList";
import "isomorphic-fetch";
import { ThunkAction } from "redux-thunk";
import { ADD_BOOKMARK_DONE, ADD_BOOKMARK_START, LIST_CREATE_DONE, LIST_CREATE_START, LIST_DELETE_DONE, LIST_DELETE_START, LIST_UPDATE_DONE, LIST_UPDATE_START, UPDATE_BOOKMARK_DONE, UPDATE_BOOKMARK_START } from "../constants/bookmark";
import { showToastMessage } from "./toast";

const messages = {
  addBookmarkToListError: "There was an error updating your list",
  addBookmarkToListSuccess: "Your item has been added.",
  createListSuccess: "Your list has been successfully created.",
  createListError: "There was an error creating your list",
  updateListError: "There was an error updating your list",
  updateListSuccess: "Your list has been updated",
  deleteListError: "There was an error deleting your list",
  deleteListSuccess: "Your list has been deleted",
  updateBookmarkSuccess: "Your bookmark has been updated",
  updateBookmarkError: "There was an error updating your bookmark",
}

export type CreateListParams = {
  userId: string;
  data: IBookmarkList,
  onDone: Function,
};

export const createList = ({ userId, data, onDone }: CreateListParams): ThunkAction<void, {}, {}, {
  type: string,
}>  =>
  async (dispatch) => {
  dispatch({
    type: LIST_CREATE_START,
  });

  let payload;

  try {
    const response = await fetch(`${window.lp.hosts.profile}/profile/api/${userId}/lists`, {
      headers: {
        "Accept": "application/json",
        "Content-Type": "application/json",
      },
      method: "POST",
      credentials: "include",
      body: JSON.stringify(data),
    });

    if (response.status !== 200) {
      const errorBody = await response.text();
      const errorObj = await JSON.parse(errorBody);
      return dispatch(showToastMessage(errorObj.message, "error"));
    }

    payload = await response.json();
  } catch (e) {
    return dispatch(showToastMessage(messages.createListError, "error"));
  }

  dispatch({
    type: LIST_CREATE_DONE,
    payload,
  });

  dispatch(showToastMessage(messages.createListSuccess));

  if (onDone) {
    onDone(payload.id);
  }
};

export const updateList = ({ userId, listId, data }: {
  userId: string;
  listId: string;
  entryId: string;
  data: IBookmarkList,
}): ThunkAction<void, {}, {}, { type: string }> => async (dispatch) => {
  dispatch({
    type: LIST_UPDATE_START,
  });

  let payload;

  try {
    const response = await fetch(`${window.lp.hosts.profile}/profile/api/${userId}/lists/${listId}.json`, {
      headers: {
        "Accept": "application/json",
        "Content-Type": "application/json",
      },
      method: "PATCH",
      credentials: "include",
      body: JSON.stringify(data),
    });

    if (response.status !== 200) {
      const errorBody = await response.text();
      const errorObj = await JSON.parse(errorBody);
      return dispatch(showToastMessage(errorObj.message, "error"));
    }

    payload = await response.json();
  } catch (e) {
    return dispatch(showToastMessage(messages.updateListError, "error"));
  }

  dispatch({
    type: LIST_UPDATE_DONE,
    payload,
  });

  dispatch(showToastMessage(messages.updateListSuccess));
};

export const deleteList = ({ userId, listId }: {
  userId: string;
  listId: string;
}): ThunkAction<Promise<void>, {}, {}, { type: string }>  => async (dispatch) => {
  dispatch({
    type: LIST_DELETE_START,
  });

  try {
    const response = await fetch(`${window.lp.hosts.profile}/profile/api/${userId}/lists/${listId}`, {
      headers: {
        Accept: "application/json",
      },
      method: "DELETE",
      credentials: "include",
    });

    if (response.status !== 204) {
      const errorBody = await response.text();
      const errorObj = await JSON.parse(errorBody);
      return dispatch(showToastMessage(errorObj.message, "error"));
    }
  } catch (e) {
    return dispatch(showToastMessage(messages.deleteListError, "error"));
  }

  dispatch({
    type: LIST_DELETE_DONE,
  });

  dispatch(showToastMessage(messages.deleteListSuccess));
};

export const addBookmarkToList = ({ userId, listId, data }: {
  userId: string;
  listId: string;
  data: IBookmark,
}): ThunkAction<Promise<void>, {}, {}, { type: string }>  => async (dispatch) => {
  dispatch({
    type: ADD_BOOKMARK_START,
    payload: data,
  });

  let payload;

  try {
    const response = await fetch(`${window.lp.hosts.profile}/profile/api/${userId}/lists/${listId}/entries.json`, {
      headers: {
        "Accept": "application/json",
        "Content-Type": "application/json",
      },
      method: "POST",
      credentials: "include",
      body: JSON.stringify(data),
    });

    if (response.status !== 200) {
      const errorBody = await response.text();
      const errorObj = await JSON.parse(errorBody);
      return dispatch(showToastMessage(errorObj.message, "error"));
    }

    payload = await response.json();
  } catch (e) {
    return dispatch(showToastMessage(messages.addBookmarkToListError, "error"));
  }

  dispatch({
    type: ADD_BOOKMARK_DONE,
    payload: {
      listId,
      bookmark: payload,
    },
  });

  dispatch(showToastMessage(messages.addBookmarkToListSuccess));
};

export interface IUpdateBookmarkDoneAction {
  type: typeof UPDATE_BOOKMARK_DONE;
  payload: {
    listId: string,
    bookmark: IBookmark,
  };
}

export const updateBookmark = ({ userId, listId, entryId, data }: {
  userId: string;
  listId: string;
  entryId: string;
  data: IBookmark,
}): ThunkAction<Promise<void>, {}, {}, { type: string }>  => async (dispatch) => {
  dispatch({
    type: UPDATE_BOOKMARK_START,
  });

  let payload;

  try {
    const response = await fetch(
      `${window.lp.hosts.profile}/profile/api/${userId}/lists/${listId}/entries/${entryId}.json`,
    {
      headers: {
        "Accept": "application/json",
        "Content-Type": "application/json",
      },
      method: "PATCH",
      credentials: "include",
      body: JSON.stringify(data),
    });

    if (response.status !== 200) {
      const errorBody = await response.text();
      const errorObj = await JSON.parse(errorBody);
      return dispatch(showToastMessage(errorObj.message, "error"));
    }

    payload = await response.json();
  } catch (e) {
    return dispatch(showToastMessage(messages.updateBookmarkError, "error"));
  }

  const action: IUpdateBookmarkDoneAction = {
    type: UPDATE_BOOKMARK_DONE,
    payload: {
      listId,
      bookmark: payload,
    }
  };

  dispatch(action);

  dispatch(showToastMessage(messages.updateBookmarkSuccess));
};
