/*
Action events used across the app.

@copyright (c) Copyright 2013-2017 Dorian Pula
@license AGPL v3
@author Dorian Pula [dorian.pula@amber-penguin-software.ca]
*/


// Polyfill for both server and client side fetch.
import 'isomorphic-fetch';

import {ThemeManager} from './theme_manager';
import {UserInfo} from  './user_info';
import {DEFAULT_USER_LOGIN} from './reducers';

export const LOAD_PAGE_ACTION = 'LOAD_ARTICLE';
export const LOAD_MENU_ACTION = 'LOAD_MENU';
export const UPDATE_SITE_INFO_ACTION = 'UPDATE_APP_SITE_INFO';
export const LOAD_INITIAL_USER_ACTION = 'INITIAL_USER';
export const UPDATE_USER_ACTION = 'UPDATE_USER';
export const LOGOUT_USER_ACTION = 'LOGOUT_USER';
export const LOAD_THEME_ACTION = 'LOAD_THEME';
export const SWITCH_THEME_ACTION = 'SWITCH_THEME';

export function fetchPage(pageSlug='') {
  return async (dispatch) => {

    const response = await fetch(`/api/pages/${pageSlug}`);
    // TODO: Add better error handling.

    const json = await response.json();

    // TODO: Figure out nicer article/block API.
    let articleContent = Reflect.get(json, 'content');
    let title = Reflect.get(json, 'title');
    if (articleContent === undefined) {
      if (pageSlug === 'error') {
        articleContent = `ERROR - No content found for "${pageSlug}"!`;
      } else {
        dispatch(fetchPage('error'));
      }
    }

    return dispatch(loadPage({slug: pageSlug, content: articleContent, title: title}));
  }
}

export function fetchSiteMenu() {
  // TODO: Retrieve the name of the site.
  return async (dispatch) => {

    const response = await fetch('/api/site/menu');
    // TODO: Add better error handling.
    const json = await response.json();

    return dispatch(loadNavigation(json.menu));
  }
}

export function fetchSiteInfo() {
  // TODO: Retrieve the name of the site.
  return async (dispatch) => {

    const response = await fetch('/api/site');

    // TODO: Add better error handling.
    const json = await response.json();

    // TODO: Avoid this extra conversion
    const appSiteInfo = {
      footer: json.config.footer,
      logo: json.config.logo,
      name: json.config.name,
      tagline: json.config.tagline,
      ...json
    };

    return dispatch(updateSiteInfo(appSiteInfo));
  }
}

export function updateSiteInfo(siteInfo) {
  return {
    type: UPDATE_SITE_INFO_ACTION,
    site: siteInfo
  };
}

export function savePage(content) {
  return async (dispatch) => {

    const response = await fetch(`/api/pages/${content.id}`, {
      method: 'POST',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        'Authorization': `JWT ${UserInfo.getUserInfo('auth_token')}`
      },
      body: JSON.stringify(content)
    });

    const json = await response.json();

    // TODO: Figure out nicer article/block API.
    let articleContent = Reflect.get(json, 'content');
    let title = Reflect.get(json, 'title');
    let articleId = Reflect.get(json, 'id');
    if (articleContent === undefined) {
      if (articleId === 'error') {
        articleContent = `ERROR - No content found for "${articleId}"!`;
      } else {
        dispatch(fetchPage('error'));
      }
    }
    return dispatch(loadPage({id: articleId, content: articleContent, title: title}));
  }
}

export function loadPage(article={content: 'Loading content...  Please wait.', title: 'Loading...'}) {
  // TODO: Extract editor setup and session info...
  return {
    type: LOAD_PAGE_ACTION,
    content: {...article}
  };
}

export function loadNavigation(menu=[]) {
  return {
    type: LOAD_MENU_ACTION,
    menu: menu
  };
}

export function switchThemes() {
  let switchedThemes = ThemeManager.switchTheme();
  return {
    type: SWITCH_THEME_ACTION,
    theme: switchedThemes.theme,
    alternativeTheme: switchedThemes.alternativeTheme,
    editorTheme: switchedThemes.editorTheme
  };
}

export function loadTheme() {
  return {
    type: LOAD_THEME_ACTION,
    theme: ThemeManager.getCurrentTheme(),
    alternativeTheme: ThemeManager.getNextTheme(),
    editorTheme: ThemeManager.getEditorTheme()
  };
}


export function initialUser() {
  return {
    type: LOAD_INITIAL_USER_ACTION,
    user: {
      token: UserInfo.getUserInfo('auth_token') || '',
      fullName: UserInfo.getUserInfo('full_name') || 'Stranger',
      accountState: ''
    }
  }
}

export function updateUser(token='', user=DEFAULT_USER_LOGIN, accountState='') {
  if (token !== '') {
    UserInfo.setUserInfo('auth_token', token);
  }
  UserInfo.setUserInfo('full_name', user.profile.fullName);
  return {
    type: UPDATE_USER_ACTION,
    user: {
      ...user,
      token: token,
      accountState: accountState
    }
  }
}

export function logoutUser(accountState='') {
  UserInfo.removeUserInfo('auth_token');
  UserInfo.removeUserInfo('full_name');
  return {
    type: LOGOUT_USER_ACTION,
    user: {
      ...DEFAULT_USER_LOGIN,
      token: '',
      accountState: accountState
    }
  }
}


export function loginUser(username, password) {
  return async (dispatch) => {

    const response = await fetch('/auth', {
      method: 'POST',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({username: username, password: password})
    });

    if (response.status !== 200 && response.status !== 401) {
      return dispatch(logoutUser(`Unable to login "${username}".`));
    }

    const json = await response.json();

    let authToken = Reflect.get(json, 'access_token');
    if (authToken !== undefined) {

      const username = Reflect.get(json, 'username');
      const userResponse = await fetch(`/api/users/${username}`,{
        method: 'GET',
        headers: {
          'Authorization': `JWT ${authToken}`,
          'Accept': 'application/json',
        },
      });
      const user = await userResponse.json();
      return dispatch(updateUser(authToken, user));
    }

    return dispatch(logoutUser(`${json.description} for "${username}".`));
  }
}
