import Immutable from 'immutable';
import React from 'react';
import WebRPC from 'webrpc';
import { updateConnectionStatus } from 'actions/status';

const TickerRecord = new Immutable.Record({
  refCount: 1,
  session: null,
  symbol: null,
  companyName: null,
  previousClose: null,
  price: null,
  askPrice: null,
  bidPrice: null,
  volume: null,
  percentChange: null,
  nominalChange: null,
  dayHigh: null,
  dayLow: null,
  fiftyTwoWeekHigh: null,
  fiftyTwoWeekLow: null,
  regPrice: null,
  regVolume: null,
  regNominalChange: null,
  regPercentChange: null
});

export const SESSION_PREMARKET = 'premarket';
export const SESSION_AFTERHOURS = 'afterhours';
export const SESSION_REGULAR = 'regular';

export default class QuoteService {
  constructor() {
    this.tickers = new Immutable.Map({});
    this.handlers = new Immutable.Map({});
  }
  connect() {
    if (this.socket) {
      return true;
    }
    this.socket = new WebRPC(process.env.QUOTE_ADDR);
    this.socket.onconnect = function(e) {
      updateConnectionStatus('quote', true);
    };
    this.socket.ondisconnect = function(e) {
      updateConnectionStatus('quote', false);
    };
    this.socket.on('connected', (data) => {
      this.addTickerSubscription(this.tickers.keySeq().toJS());
    });
    this.socket.on('quote', this.receiveQuote.bind(this));
  }

  receiveQuote(quote) {
    if (!this.tickers.has(quote.Symbol)) {
      return;
    }
    const processedQuote = this.processQuote(quote);
    this.tickers = this.tickers.set(quote.Symbol, processedQuote);
    this.handlers.get(quote.Symbol).forEach((fn) => fn(processedQuote.toJS()));
  }

  processQuote(quote) {
    let tickerData = this.tickers.get(quote.Symbol);
    if (quote.Category === 'initial') {
      tickerData = tickerData
                    .set('companyName', quote.Detail.CompanyName)
                    .set('previousClose', quote.Detail.PreviousClose)
                    .set('dayHigh', quote.Detail.DayHigh)
                    .set('dayLow', quote.Detail.DayLow)
                    .set('fiftyTwoWeekHigh', quote.Detail.FiftyTwoWeekHigh)
                    .set('fiftyTwoWeekLow', quote.Detail.FiftyTwoWeekLow)
                    .set('percentChange', quote.SessionQuote.PercentChange);
    } else {
      tickerData = tickerData
                    .set('percentChange', quote.SessionQuote.PercentChange * 100);
    }
    tickerData = tickerData
                  .set('session', quote.Session)
                  .set('askPrice', quote.SessionQuote.Ask)
                  .set('bidPrice', quote.SessionQuote.Bid)
                  .set('price', quote.SessionQuote.Last)
                  .set('volume', quote.SessionQuote.Volume)
                  .set('nominalChange', quote.SessionQuote.NominalChange);
    if (quote.Session === SESSION_REGULAR) {
      tickerData = tickerData
                    .set('regPrice', quote.SessionQuote.Price)
                    .set('regVolume', quote.SessionQuote.Volume)
                    .set('regPercentChange', quote.SessionQuote.PercentChange * 100)
                    .set('regNominalChange', quote.SessionQuote.NominalChange);
    } else {
      tickerData = tickerData
                    .set('regPrice', quote.Summary.Last)
                    .set('regVolume', quote.Summary.Volume)
                    .set('regPercentChange', quote.Summary.PercentChange * 100)
                    .set('regNominalChange', quote.Summary.NominalChange);
    }

    return tickerData;
  }

  addTickerSubscription(symbol) {
    if (typeof symbol !== 'string') {
      if (symbol.length) {
        this.socket.emit('join', symbol);
      }
    } else {
      this.socket.emit('join', [symbol]);
    }
  }
  removeTickerSubscription(symbol) {
    if (typeof symbol !== 'string') {
      if (symbol.length) {
        this.socket.emit('leave', symbol);
      }
    } else {
      this.socket.emit('leave', [symbol]);
    }
  }
  getTicker(symbol) {
    return this.tickers.get(symbol);
  }
  // Component Subscribers
  addSubscriber(entityId, props, handler) {
    if (this.tickers.has(props.symbol)) {
      this.tickers = this.tickers.setIn([props.symbol, 'refCount'], this.tickers.getIn([props.symbol, 'refCount']) + 1);
      this.handlers = this.handlers.setIn([props.symbol, entityId], handler);
    } else {
      this.tickers = this.tickers.set(props.symbol, new TickerRecord({symbol: props.symbol}));
      this.handlers = this.handlers.set(props.symbol, new Immutable.Map({[entityId]: handler}));
      this.addTickerSubscription(props.symbol);
    }
    return this.tickers.get(props.symbol).toJS();
  }
  updateSubscriber(entityId, props, oldProps, handler) {
    // this.removeSubscriber(entityId, oldProps);
    // handler(this.addSubscriber(entityId, props, handler));
  }
  removeSubscriber(entityId, props) {
    if (this.tickers.getIn([props.symbol, 'refCount']) === 1) {
      this.tickers = this.tickers.delete(props.symbol);
      this.handlers = this.handlers.delete(props.symbol);
      this.removeTickerSubscription(props.symbol);
    } else {
      const before = this.tickers.getIn([props.symbol, 'refCount']);
      this.tickers = this.tickers.setIn([props.symbol, 'refCount'], this.tickers.getIn([props.symbol, 'refCount']) - 1);
      this.handlers = this.handlers.deleteIn([props.symbol, entityId]);
    }
  }
}
