import SwimTrackerWebsocketConnection from "../data_processing/SwimTrackerWebsocketConnection";
import DataAnalysis from "../data_processing/DataAnalysis";
import { List } from "immutable";

export const ConnState = {
  DISCONNECTED: 'disconnected',
  CONNECTED_STOPPED: 'connected_stopped',
  CONNECTED_RUNNING: 'connected_running',
  CONNECTED_STARTING: 'connected_starting', // start message sent, but device hasn't ack'ed it yet
  CONNECTED_STOPPING: 'connected_stopping'  // stop message sent..
}

export const WifiState = {
  UNKNOWN: 'unknown',
  STA: 'sta', // connected to regular wifi
  AP_PROVISIONING: 'ap_provisioning', // acting as access point for provisioning
  AP_SECURE: 'ap_secure', // acting as access point, password has been set
}

// -------------------------------------------- Actions ---------------------------------------------

export const DEVICE_DISCONNECT = "DEVICE_DISCONNECT";
export const DEVICE_CONNECT = "DEVICE_CONNECT";
export const SESSION_STARTED = "SESSION_STARTED";
export const SESSION_STOPPED = "SESSION_STOPPED";
export const SESSION_NEW_DATA = "SESSION_NEW_DATA";

export const START_SESSION = "START_SESSION";
export const STOP_SESSION = "STOP_SESSION";

export const WIFI_SET_STATE = "WIFI_SET_STATE";

export const reportNewWifiState = (newStateStr) => ({
  type: WIFI_SET_STATE,
  newStateStr: newStateStr
});

export const reportSessionStarted = (sessionId) => ({
  type: SESSION_STARTED,
  sessionId: sessionId
});

export const reportSessionStopped = () => ({
  type: SESSION_STOPPED
});

export const reportNewSessionData = (allMeasurements, analysis) => ({
  type: SESSION_NEW_DATA,
  data: allMeasurements,
  analysis: analysis
});

export const reportDeviceConnect = () => ({
  type: DEVICE_CONNECT
});

export const reportDeviceDisconnect = () => ({
  type: DEVICE_DISCONNECT
});

export const startSession = () => ({
  type: START_SESSION
});

export const stopSession = () => ({
  type: STOP_SESSION
});

// -------------------------------------------- Device coupling -------------------------------------

export class DeviceReduxCoupling {
  constructor(reduxStore) {
    this.reduxStore = reduxStore;
    this.analysis = new DataAnalysis();

    this.conn = null;

    this.reduxStore.subscribe(this._onStateChange);
    this._onStateChange();
  }

  _onStateChange = () => {
    const state = this.reduxStore.getState();

    if (this.conn === null || (state.settings.swimTrackerHost != this.conn.swimTrackerHost)) {
      this.conn = new SwimTrackerWebsocketConnection(state.settings.swimTrackerHost,
        this._onNewData,
        (sessionId) => this.reduxStore.dispatch(reportSessionStarted(sessionId)),
        () => this.reduxStore.dispatch(reportSessionStopped()),
        (response) => this.reduxStore.dispatch(reportNewWifiState(response["state"])),
        () => this.reduxStore.dispatch(reportDeviceConnect()),
        () => this.reduxStore.dispatch(reportDeviceDisconnect())
      );
    }
    if (state.deviceState.connState === ConnState.CONNECTED_STARTING) {
      console.log("sending start command to connection");
      this.conn.sendStartCommand();
    }
    else if (state.deviceState.connState === ConnState.CONNECTED_STOPPING)
      this.conn.sendStopCommand();
  }

  _onNewData = (newData) => {
    const state = this.reduxStore.getState();
    const allMeasurements = state.deviceState.measurements.concat(List(newData));
    const analysisResult = this.analysis.analyze(state.settings.analysis, state.deviceState.sessionId, allMeasurements);
    this.reduxStore.dispatch(reportNewSessionData(allMeasurements, analysisResult));
  }
};

// -------------------------------------------- Reducer -----------------------------------------------

const INITIAL_ANALYSIS = {
  'peaks': List(),
  'totalTime': null,
  'totalMomentum': null,
  'peakMax': null,
  'momentumWindow': null,
  'peakMaxWindow': null,
};

const INITIAL_DEVICE_STATE = {
  connState: ConnState.DISCONNECTED,
  wifiState: WifiState.UNKNOWN,
  sessionId: 0,
  measurements: List(),
  analysis: INITIAL_ANALYSIS,
};

export const deviceStateReducer = (state = INITIAL_DEVICE_STATE, action) => {
  switch (action.type) {
    case SESSION_NEW_DATA:
      const res = {
        ...state,
        measurements: action.data,
        analysis: { ...state.analysis, ...action.analysis }
      };
      return res;
    case DEVICE_CONNECT:
      return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STOPPED };
    case DEVICE_DISCONNECT:
      return { ...INITIAL_DEVICE_STATE, connState: ConnState.DISCONNECTED };
    case SESSION_STARTED:
      return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_RUNNING, sessionId: action.sessionId };
    case SESSION_STOPPED:
      return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STOPPED };
    case START_SESSION:
      if (state.connState === ConnState.SESSION_STARTED)
        return state;
      return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STARTING };
    case STOP_SESSION:
      if (state.connState === ConnState.SESSION_STOPPED)
        return state;
      return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STOPPING };
    case WIFI_SET_STATE:
      let wifState = WifiState.UNKNOWN;
      if (action.newStateStr === "STATION_MODE") { wifState = WifiState.STA; }
      else if (action.newStateStr === "AP_PROVISIONING") { wifState = WifiState.AP_PROVISIONING; }
      else if (action.newStateStr === "AP_SECURE") { wifState = WifiState.AP_SECURE; }
      return { ...state, wifiState: wifState };
    default:
      //console.log("Unhandled state in deviceStateReducer", action, action.type, "state", state);
      return state;
  }
};



