import store from '../store';
import {fetch} from './fetch';
import {logout} from 'actions/session';
import {requestWatchlists, receiveWatchlists} from 'actions/watchlists';
import forEach from 'lodash/forEach';
import map from 'lodash/map';
import { promiseFinally } from 'utils/promise';

function checkStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    if (response.statusText === 'No Content' || response.statusText === 'DELETED') {
      return {};
    }
    return response.json();
  } else if (response.status > 100) {
    return response.json().then(data => {
      if (data.data) {
        throw data.data[0];
      } else {
        throw response.statusText;
      }
    });
  }
}

export default class UserService {
  constructor() {
    this.alerts = null;
    this.getAlerts = this.getAlerts.bind(this);
  }
  session() {
    return store.getState().session;
  }
  handleError(type, response) {
    return response.json().then(x => {
      const e = new Error;
      e.message = x.Error;
      e.name = type;
      throw e;
    });
  }
  handleResponse(response) {
    switch (response.status) {
    case 500:
      return this.handleError('ServerError', response);
    case 400:
      return this.handleError('RequestError', response);
    case 401:
      store.dispatch(logout());
      return this.handleError('AuthError', response);
    case 403:
      return this.handleError('PermissionError', response);
    default:
    }
    return response.json();
  }
  getWatchlists() {
    const { authKey } = this.session();
    store.dispatch(requestWatchlists());
    return fetch(`${process.env.SERVICES_ROOT}/services/watchlist/bzuser/portfolio?status=enabled`, {
      headers: {
        'accept': 'application/json',
        'content-type': 'application/json',
        'x-device-key': authKey
      },
      method: 'get'
    })
    .then(checkStatus)
    .then(data => {
      const watchlists = {};
      forEach(data.data, w =>
        watchlists[w.portfolio_id] = {
          id: w.portfolio_id,
          name: w.portfolio_name,
          tickers: map(w.alerts, a => {
            return {id: a.alert_id, symbol: a.alert_name, emailAlertsEnabled: a.send_realtime, sound: a.sound};
          })
        }
      );
      store.dispatch(receiveWatchlists(watchlists));
      return data.data;
    });
  }
  createWatchlist(name, symbols = []) {
    const data = {
      portfolio_name: name,
      status: true,
      send_summary: false,
      alerts: map(symbols, symbol => {
        return {
          alert_name: symbol,
          send_realtime: false,
          status: true,
          type: 'ticker'
        };
      })
    };
    return new Promise((resolve, reject) => {
      const { authKey } = this.session();
      fetch(`${process.env.SERVICES_ROOT}/services/watchlist/bzuser/portfolio`, {
        headers: {
          'accept': 'application/json',
          'content-type': 'application/json',
          'x-device-key': authKey
        },
        body: JSON.stringify(data),
        method: 'post'
      })
      .then(checkStatus)
      .then(data => {
        // Yeah, this is fucked but oh well
        resolve(data.data[Object.keys(data.data)[0]]);
      })
      .catch(err => reject(err));
    });
  }
  updateWatchlist(watchlistId, name) {
    const { authKey } = this.session();
    const data = {
      portfolio_id: watchlistId,
      portfolio_name: name
    };
    return fetch(`${process.env.SERVICES_ROOT}/services/watchlist/bzuser/portfolio/${watchlistId}/`, {
      headers: {
        'accept': 'application/json',
        'content-type': 'application/json',
        'x-device-key': authKey
      },
      body: JSON.stringify(data),
      method: 'put'
    })
    .then(checkStatus);
  }
  deleteWatchlist(watchlistId) {
    const { authKey } = this.session();
    return fetch(`${process.env.SERVICES_ROOT}/services/watchlist/bzuser/portfolio/${watchlistId}/`, {
      headers: {
        'accept': 'application/json',
        'content-type': 'application/json',
        'x-device-key': authKey
      },
      method: 'delete'
    })
    .then(checkStatus);
  }
  addWatchlistSymbol(watchlistId, symbol) {
    const { authKey } = this.session();
    const data = {
      portfolio_id: watchlistId,
      alert_name: symbol,
      type: 'ticker',
      send_realtime: false,
      status: true
    };

    return fetch(`${process.env.SERVICES_ROOT}/services/watchlist/bzuser/alert/`, {
      headers: {
        'accept': 'application/json',
        'content-type': 'application/json',
        'x-device-key': authKey},
      body: JSON.stringify(data),
      method: 'post'
    })
    .then(checkStatus)
    .then(data => {
      // What's returned from the server is fucking terrible...*cries*
      const alerts = data.data[0];
      const ticker = alerts[Object.keys(alerts)[0]];
      return {
        id: ticker.alert_id,
        symbol: ticker.alert_name,
        emailAlertsEnabled: ticker.send_realtime
      };
    });
  }
  addWatchlistSymbols(watchlistId, symbols) {
    const { authKey } = this.session();
    const data = [];
    for (const sym of symbols) {
      data.push({
        portfolio_id: watchlistId,
        alert_name: sym,
        type: 'ticker',
        send_realtime: false,
        status: true
      });
    }

    return fetch(`${process.env.SERVICES_ROOT}/services/watchlist/bzuser/alert/`, {
      headers: {
        'accept': 'application/json',
        'content-type': 'application/json',
        'x-device-key': authKey},
      body: JSON.stringify(data),
      method: 'post'
    })
    .then(checkStatus)
    .then(data => {
      const ret = [];
      // What's returned from the server is fucking terrible...*cries*
      for (const index in data.data) {
        const alerts = data.data[index];
        const ticker = alerts[Object.keys(alerts)[0]];
        ret.push({
          id: ticker.alert_id,
          symbol: ticker.alert_name,
          emailAlertsEnabled: ticker.send_realtime
        });
      }
      return ret;
    });
  }

  deleteWatchlistSymbol(alertId) {
    const { authKey } = this.session();
    return fetch(`${process.env.SERVICES_ROOT}/services/watchlist/bzuser/alert/${alertId}/`, {
      headers: {
        'accept': 'application/json',
        'content-type': 'application/json',
        'x-device-key': authKey
      },
      method: 'delete'
    })
    .then(checkStatus)
    .then(data => {
      // Update what we are alerting on
      this.getAlerts();

      return true;
    });
  }
  updateIndividualWatchlistAlert(alertId, realtimeEnabled, alertSound) {
    const { authKey } = this.session();
    const data = {
      alert_id: alertId,
    };

    if (realtimeEnabled !== null) {
      data.send_realtime = realtimeEnabled;
    }
    if (alertSound !== null) {
      data.sound = alertSound;
    }

    return new Promise((resolve, reject) => {
      fetch(`${process.env.SERVICES_ROOT}/services/watchlist/bzuser/alert/${alertId}/`, {
        headers: {
          'accept': 'application/json',
          'content-type': 'application/json',
          'x-device-key': authKey
        },
        body: JSON.stringify(data),
        method: 'put'
      })
      .then(checkStatus)
      .then(data => {
        // Yeah, this is fucked but oh well
        resolve(data.data[Object.keys(data.data)[0]]);
      })
      .catch(err => reject(err));
    });
  }
  updateWatchlistAlert(alertId, realtimeEnabled, alertSound) {
    return promiseFinally(this.updateIndividualWatchlistAlert(alertId, realtimeEnabled, alertSound),
      this.getAlerts);
  }
  updateWatchlistAlerts(alertIds, realtimeEnabled, alertSound) {
    const promises = alertIds.map(
      (alertId) => this.updateIndividualWatchlistAlert(alertId, realtimeEnabled, alertSound)
    );

    return promiseFinally(Promise.all(promises), this.getAlerts);
  }
  getAlerts() {
    const { authKey } = this.session();
    return fetch(`${process.env.SERVICES_ROOT}/services/watchlist/bzuser/alert/`, {
      headers: {
        'accept': 'application/json',
        'content-type': 'application/json',
        'x-device-key': authKey
      },
      method: 'get'
    })
    .then(checkStatus)
    .then(data => {
      this.alerts = Object.keys(data.data).map(key => data.data[key]);
      return this.alerts;
    });
  }
  getAlertChannels() {
    const { authKey } = this.session();
    return fetch(`${process.env.SERVICES_ROOT}/services/watchlist/bzuser/channel`, {
      headers: {
        'accept': 'application/json',
        'content-type': 'application/json',
        'x-device-key': authKey
      },
      method: 'get'
    })
    .then(checkStatus)
    .then(data => data.data);
  }
  updateAlertChannel(channelId, subscriptionType) {
    const { authKey } = this.session();
    const data = {
      channel_id: channelId,
      subscription_type: subscriptionType
    };
    return fetch(`${process.env.SERVICES_ROOT}/services/watchlist/bzuser/channel/${channelId}/`, {
      headers: {
        'accept': 'application/json',
        'content-type': 'application/json',
        'x-device-key': authKey
      },
      body: JSON.stringify(data),
      method: 'put'
    })
    .then(checkStatus)
    .then(data => {
      this.getAlerts();
      return data.data;
    });
  }
  deleteAlertChannel(channelId) {
    const { authKey } = this.session();
    return fetch(`${process.env.SERVICES_ROOT}/services/watchlist/bzuser/channel/${channelId}/`, {
      headers: {
        'accept': 'application/json',
        'content-type': 'application/json',
        'x-device-key': authKey
      },
      method: 'delete'
    })
    .then(checkStatus)
    .then(data => {
      this.getAlerts();
      return data;
    });
  }
}
