import moment from 'moment';
import Immutable from 'immutable';

import { widgetAddReducer } from '../reducers/widgets';
import {
  SWITCH_WORKSPACE,
  ADD_WORKSPACE,
  REMOVE_WORKSPACE,
  REMOVE_WIDGET,
  CHANGE_WORKSPACE_NAME,
  LOAD_LAYOUT
} from 'actions/workspaces';
import {
  ADD_WIDGET_NEWSFEED,
  ADD_WIDGET_CALENDAR,
  ADD_WIDGET_SECURITY,
  ADD_WIDGET_WATCHLIST
} from 'actions/widgets';
import {
  WATCHLIST_WIDGET_TOGGLE_DISPLAY,
  WATCHLIST_POPOUT_TOGGLE_DISPLAY,
  WIDGET_SELECT_WATCHLIST,
  POPOUT_SELECT_WATCHLIST
} from 'actions/watchlists';
import {
  FEED_WIDGET_CHANGE_FILTERS,
  FEED_POPOUT_CHANGE_FILTERS,
  FEED_WIDGET_CHANGE_SPACING,
  FEED_POPOUT_CHANGE_SPACING,
  FEED_WIDGET_CHANGE_TEXT,
  FEED_POPOUT_CHANGE_TEXT,
  FEED_WIDGET_CHANGE_THEME_COLOR,
  FEED_POPOUT_CHANGE_THEME_COLOR,
  FEED_WIDGET_CHANGE_THEME_TARGET,
  FEED_POPOUT_CHANGE_THEME_TARGET,
  FEED_WIDGET_ADD_THEME,
  FEED_POPOUT_ADD_THEME,
  FEED_WIDGET_REMOVE_THEME,
  FEED_POPOUT_REMOVE_THEME
} from 'actions/feeds';
import {
  SECURITY_WIDGET_CHANGE_SYMBOL,
  SECURITY_POPOUT_CHANGE_SYMBOL,
  SECURITY_WIDGET_TOGGLE_DISPLAY,
  SECURITY_POPOUT_TOGGLE_DISPLAY,
} from 'actions/securities';
import {
  getWidgetMapById,
  mapAllWidgets
} from 'utils/workspaces';

import {
  FeedTheme
} from './widgets';

import { securityReducer, newSecurity } from './securities';
import { calendarsReducer, newCalendar } from './calendars';


export const Workspace = new Immutable.Record({
  widgets: new Immutable.List(),
  theme: 'dark',
  name: 'Workspace 1'
});

// This "reducer" allows us to perform state changes on a specific widget object
export function widgetMethodsReducer(oldWidgetData, action) {
  let widgetData = oldWidgetData;

  widgetData = securityReducer(widgetData, action);
  widgetData = calendarsReducer(widgetData, action);

  switch (action.type) {
  // Feed Widget Events
  case FEED_WIDGET_CHANGE_SPACING:
  case FEED_POPOUT_CHANGE_SPACING:
    return widgetData.set('headerSpacing', action.headerSpacing);
  case FEED_WIDGET_CHANGE_TEXT:
  case FEED_POPOUT_CHANGE_TEXT:
    return widgetData.set('textSize', action.textSize);
  case FEED_WIDGET_CHANGE_FILTERS:
  case FEED_POPOUT_CHANGE_FILTERS:
    return widgetData.set('filters', Immutable.fromJS(action.filters));
  case FEED_WIDGET_CHANGE_THEME_COLOR:
  case FEED_POPOUT_CHANGE_THEME_COLOR:
    return widgetData.setIn(['themes', action.themeId, 'hue'], action.hue);
  case FEED_WIDGET_CHANGE_THEME_TARGET:
  case FEED_POPOUT_CHANGE_THEME_TARGET:
    return widgetData.setIn(['themes', action.themeId, 'target'], action.target)
                     .setIn(['themes', action.themeId, 'category'], action.category);
  case FEED_WIDGET_ADD_THEME:
  case FEED_POPOUT_ADD_THEME:
    return widgetData.set('themes', widgetData.get('themes').push(new FeedTheme()));
  case FEED_WIDGET_REMOVE_THEME:
  case FEED_POPOUT_REMOVE_THEME:
    return widgetData.deleteIn(['themes', action.themeId]);

  // Watchlist Widget Events
  case WIDGET_SELECT_WATCHLIST:
  case POPOUT_SELECT_WATCHLIST:
    return widgetData.set('watchlistId', action.watchlistId);
  case WATCHLIST_WIDGET_TOGGLE_DISPLAY:
  case WATCHLIST_POPOUT_TOGGLE_DISPLAY:
    return widgetData.setIn(['display', action.display, 'visible'], !widgetData.getIn(['display', action.display, 'visible']));
  default:
    return widgetData;
  }
}

function migrateVersion(oldState, version) {
  let state = oldState; // eslint-disable-line prefer-const
  // This should be a series of if statements, checking if version is less than
  // some value in increasing order of values.
  // Use mapAllWidgets to change all widgets

  // Security Widget refactor
  if (version < 2) {
    state = mapAllWidgets((oldWidget) => {
      let widget = oldWidget;
      if (widget.get('type') === 'security') {
        widget = widget.set('data', newSecurity(widget.getIn(['data', 'symbol'])));
      }
      return widget;
    }, state);
  }

  // Calendar Widget Refactor
  if (version < 3) {
    state = mapAllWidgets((oldWidget) => {
      if (widget.get('type') === 'calendar') {
        return oldWidget.set('data', newCalendar(oldWidget.getIn(['data', 'parameters'])));
      }
      return oldWidget;
    });
  }
  return state;
}

const InitialWorkspaceState = new Immutable.Record({
  nextWidgetId: 0,
  activeWorkspace: 0,
  workspaceList: new Immutable.List([new Workspace()]),
});

export default function workspacesReducer(oldWorkspaces = new InitialWorkspaceState(), action) {
  let workspaces = oldWorkspaces;
  // We have to check for 'widgetId' in the payload first since widgetMethodsReducer
  // acts on a widget's data, not the entire list of workspaces. So, we need to
  // have a widgetId that we can use to identify the widget to call it on.
  // TODO: Remove check for payload in action once everything is using standarAction
  if ('payload' in action && 'widgetId' in action.payload) {
    const map = getWidgetMapById(action.payload.widgetId);
    if (map[0] !== null) {
      workspaces = workspaces.updateIn(['workspaceList', map[0], 'widgets', map[1], 'data'], data => widgetMethodsReducer(data, action));
    }
  }
  switch (action.type) {
  // Widget-level methods
  case FEED_WIDGET_REMOVE_THEME:
  case FEED_WIDGET_ADD_THEME:
  case FEED_WIDGET_CHANGE_THEME_TARGET:
  case FEED_WIDGET_CHANGE_THEME_COLOR:
  case FEED_WIDGET_CHANGE_FILTERS:
  case FEED_WIDGET_CHANGE_SPACING:
  case FEED_WIDGET_CHANGE_TEXT:
  case WATCHLIST_WIDGET_TOGGLE_DISPLAY:
  case WIDGET_SELECT_WATCHLIST:
    const map = getWidgetMapById(action.widgetId);
    if (map[0] === null) {
      return workspaces;
    }
    return workspaces.updateIn(['workspaceList', map[0], 'widgets', map[1], 'data'], data => widgetMethodsReducer(data, action));
  // Add widget methods
  case ADD_WIDGET_WATCHLIST:
  case ADD_WIDGET_CALENDAR:
  case ADD_WIDGET_SECURITY:
  case ADD_WIDGET_NEWSFEED:
    const newWidget = widgetAddReducer(workspaces.get('nextWidgetId'), action);
    let updatedWorkspace = workspaces.getIn(['workspaceList', workspaces.get('activeWorkspace')]);
    updatedWorkspace = updatedWorkspace.set('widgets', updatedWorkspace.get('widgets').push(newWidget));
    return workspaces
      .set('nextWidgetId', workspaces.get('nextWidgetId') + 1)
      .set('workspaceList', workspaces.get('workspaceList').set(workspaces.get('activeWorkspace'), updatedWorkspace));
  // Remove widget method
  case REMOVE_WIDGET:
    const widgetIndex = getWidgetMapById(action.widgetId);
    return workspaces.deleteIn(['workspaceList', widgetIndex[0], 'widgets', widgetIndex[1]]);
  // Workspace-level methods
  case ADD_WORKSPACE:
    return workspaces.set('workspaceList', workspaces.get('workspaceList').push(new Workspace({name: 'Workspace ' + (workspaces.get('workspaceList').size + 1)})));
  case REMOVE_WORKSPACE:
    const activeWorkspace = workspaces.get('activeWorkspace');
    let newActiveWorkspace = activeWorkspace;
    if (action.workspaceIndex <= activeWorkspace) {
      newActiveWorkspace--;
      // verify workspace we would set as the new one isn't less than zero
      if (newActiveWorkspace < 0) {
        newActiveWorkspace = 0;
      }
    }
    return workspaces
      .set('workspaceList', workspaces.get('workspaceList').delete(action.workspaceIndex))
      .set('activeWorkspace', newActiveWorkspace);
  case SWITCH_WORKSPACE:
    return workspaces.set('activeWorkspace', action.index);
  case CHANGE_WORKSPACE_NAME:
    return workspaces.setIn(['workspaceList', workspaces.get('activeWorkspace'), 'name'], action.name);
  case LOAD_LAYOUT:
    return migrateVersion(Immutable.fromJS(action.layout), action.layoutVersion);
  default:
    return workspaces;
  }
}
