import { createStore, Store } from 'vuex'

import { socket } from '../plugins/socket'

import { DeviceViewModel } from '../common/DeviceTypes'
import { BoardInterface, PortInterface } from '../common/BoardTypes'
import { MappingConfiguration, VideohubConfiguration } from '../common/MappingTypes'
import { LogEvent } from '../common/LogTypes'
import { AtemKeySyncConfiguration } from '../common/KeySyncTypes'
import { NetworkConfiguration } from '../common/SystemTypes'

interface AppState {
  boards: BoardInterface[]
  devices: DeviceViewModel[]
  gpiMappings: MappingConfiguration[]
  gpoMappings: MappingConfiguration[]
  videohubMappings: VideohubConfiguration[]
  keySync: AtemKeySyncConfiguration[]
  ports: PortMapping,
  log: LogEvent[],
  networkConfig: NetworkConfiguration,
  companionUpdateResult: string,
  remoteConnectionActive: boolean,
  remoteConnectionEnabled: boolean,
  backups: string[]
}
interface PortMapping {
  [id: string]: PortInterface
}

const data: AppState = {
  boards: [],
  devices: [],
  gpiMappings: [],
  gpoMappings: [],
  videohubMappings: [],
  keySync: [],
  ports: {},
  log: [],
  networkConfig: { ip: '', netmask: 0, gateway: '', nameserver: '' },
  companionUpdateResult: '',
  remoteConnectionActive: false,
  remoteConnectionEnabled: false,
  backups: []
}


const store: Store = createStore({
  state: data,
  mutations: {
    SetBoards(state, payload) {
      state.boards.splice(0, state.boards.length)
      for (const item of payload.data) {
        state.boards.push(item)

        for (const port of item.inputs) {
          state.ports[port.id] = port
        }

        for (const port of item.outputs) {
          state.ports[port.id] = port
        }
      }
    },
    SetDevices(state, payload) {
      state.devices.splice(0, state.devices.length)
      for (const item of payload.data) {
        state.devices.push(item)
      }
    },
    SetGpiMappings(state, payload) {
      state.gpiMappings.splice(0, state.gpiMappings.length)
      for (const item of payload.data) {
        state.gpiMappings.push(item)
      }
    },
    SetGpoMappings(state, payload) {
      state.gpoMappings.splice(0, state.gpoMappings.length)
      for (const item of payload.data) {
        state.gpoMappings.push(item)
      }
    },
    SetVideohubMappings(state, payload) {
      state.videohubMappings.splice(0, state.videohubMappings.length)
      for (const item of payload.data) {
        state.videohubMappings.push(item)
      }
    },
    SetKeySyncSettings(state, payload) {
      state.keySync.splice(0, state.keySync.length)
      for (const item of payload.data) {
        state.keySync.push(item)
      }
    },
    SetIoState(state, payload) {
      if (!payload || !payload.data || !payload.data.id || payload.data.value === undefined) {
        return
      }

      const port = state.ports[payload.data.id]
      if (port !== undefined) {
        port.value = payload.data.value
      }
    },
    SetDeviceStatus(state, payload) {
      const device = state.devices.find(d => d.config.id === payload.id)
      if (device) {
        device.status = payload.status
      }
    },
    SetLogEvents(state, payload) {
      state.log.splice(0, state.log.length)
      state.log.push(...payload.data)
    },
    AddLogEvent(state, payload) {
      state.log.push(payload.data)
    },
    SetNetworkConfig(state, payload) {
      Object.assign(state.networkConfig, payload.data)
    },
    SetCompanionUpdateResult(state, payload) {
      state.companionUpdateResult = payload.data
    },
    SetRemoteConnection(state, payload) {
      state.remoteConnectionActive = payload.data !== undefined && payload.data.connected === true
      state.remoteConnectionEnabled = payload.data !== undefined && payload.data.enabled === true
    },
    SetBackups(state, payload) {
      state.backups.splice(0, state.backups.length)
      for (const item of payload.data) {
        state.backups.push(item)
      }
    },
  },
  getters: {
    getDevice: (state) => (id: string) => {
      for (const item of state.devices) {
        if (item.config.id === id) return item
      }
      return undefined
    }
  },
  actions: {
    SOCKET_boards(state, data) {
      state.commit('SetBoards', data)
    },
    SOCKET_devices(state, data) {
      state.commit('SetDevices', data)
    },
    SOCKET_gpiMappings(state, data) {
      state.commit('SetGpiMappings', data)
    },
    SOCKET_gpoMappings(state, data) {
      state.commit('SetGpoMappings', data)
    },
    SOCKET_videohubMappings(state, data) {
      state.commit('SetVideohubMappings', data)
    },
    SOCKET_keySync(state, data) {
      state.commit('SetKeySyncSettings', data)
    },
    SOCKET_ioChange(state, data) {
      state.commit('SetIoState', data)
    },
    SOCKET_deviceStatusChanged(state, data) {
      state.commit('SetDeviceStatus', data)
    },
    SOCKET_logEntries(state, data) {
      state.commit('SetLogEvents', data)
    },
    SOCKET_logEntry(state, data) {
      state.commit('AddLogEvent', data)
    },
    SOCKET_networkConfig(state, data) {
      state.commit('SetNetworkConfig', data)
    },
    SOCKET_companionUpdateResult(state, data) {
      state.commit('SetCompanionUpdateResult', data)
    },
    SOCKET_remoteConnection(state, data) {
      state.commit('SetRemoteConnection', data)
    },
    SOCKET_backups(state, data) {
      state.commit('SetBackups', data)
    }
  },
  modules: {
  }
})

socket.onAny((event: string, ...args) => {
  if (args !== undefined && args.length > 0) {
    store.dispatch('SOCKET_' + event, args[0])
  }
})

export default store