export interface Action {
  type: string;
  payload: Record<string, any>
  monaco: any,
  editor: any
}

export const initialState = {}

export const reducerActions = (models = initialState, action: Action) => {
  const monaco = action.monaco
  const editor = action.editor
  switch (action.type) {
    case 'ADD_MODEL': {
      if (!editor) return models
      const uri = action.payload.uri
      const value = action.payload.value
      const language = action.payload.language
      const readOnly = action.payload.readOnly
      if (models[uri]) return models // already existing
      models[uri] = { language, uri, readOnly }
      const model = monaco.editor.createModel(value, language, monaco.Uri.parse(uri))
      models[uri].model = model
      model.onDidChangeContent(() => action.payload.events.onDidChangeContent(uri))
      return models
    }
    case 'DISPOSE_MODEL': {
      const uri = action.payload.uri
      const model = models[uri]?.model
      if (model) model.dispose()
      delete models[uri]
      return models
    }
    case 'SET_VALUE': {
      if (!editor) return models
      const uri = action.payload.uri
      const value = action.payload.value
      const model = models[uri]?.model
      if (model) {
        model.setValue(value)
      }
      return models
    }
    case 'REVEAL_LINE': {
      if (!editor) return models
      const line = action.payload.line
      const column = action.payload.column
      editor.revealLine(line)
      editor.setPosition({ column, lineNumber: line })
      return models
    }
    case 'FOCUS': {
      if (!editor) return models
      editor.focus()
      return models
    }
    case 'SET_FONTSIZE': {
      if (!editor) return models
      const size = action.payload.size
      editor.updateOptions({ fontSize: size })
      return models
    }
    case 'SET_WORDWRAP': {
      if (!editor) return models
      const wrap = action.payload.wrap
      editor.updateOptions({ wordWrap: wrap ? 'on' : 'off' })
      return models
    }
  }
}

export const reducerListener = (plugin, dispatch, monaco, editor, events) => {
  plugin.on('editor', 'addModel', (value, language, uri, readOnly) => {
    dispatch({
      type: 'ADD_MODEL',
      payload: { uri, value, language, readOnly, events },
      monaco,
      editor
    })
  })

  plugin.on('editor', 'disposeModel', (uri) => {
    dispatch({
      type: 'DISPOSE_MODEL',
      payload: { uri },
      monaco,
      editor
    })
  })

  plugin.on('editor', 'setValue', (uri, value) => {
    dispatch({
      type: 'SET_VALUE',
      payload: { uri, value },
      monaco,
      editor
    })
  })

  plugin.on('editor', 'revealLine', (line, column) => {
    dispatch({
      type: 'REVEAL_LINE',
      payload: { line, column },
      monaco,
      editor
    })
  })

  plugin.on('editor', 'focus', () => {
    dispatch({
      type: 'FOCUS',
      payload: {},
      monaco,
      editor
    })
  })

  plugin.on('editor', 'setFontSize', (size) => {
    dispatch({
      type: 'SET_FONTSIZE',
      payload: { size },
      monaco,
      editor
    })
  })

  plugin.on('editor', 'setWordWrap', (wrap) => {
    dispatch({
      type: 'SET_WORDWRAP',
      payload: { wrap },
      monaco,
      editor
    })
  })
}
