const url = require('url')
const {shell} = require('electron')
const _ = require('underscore-plus')

const LINK_SCOPE_REGEX = /markup\.underline\.link/

module.exports = {
  activate () {
    this.commandDisposable = atom.commands.add('atom-text-editor', 'link:open', () => this.openLink())
  },

  deactivate () {
    this.commandDisposable.dispose()
  },

  openLink () {
    const editor = atom.workspace.getActiveTextEditor()
    if (editor == null) return

    let link = this.linkUnderCursor(editor)
    if (link == null) return

    if (editor.getGrammar().scopeName === 'source.gfm') {
      link = this.linkForName(editor, link)
    }

    const {protocol} = url.parse(link)
    if (protocol === 'http:' || protocol === 'https:' || protocol === 'atom:') shell.openExternal(link)
  },

  // Get the link under the cursor in the editor
  //
  // Returns a {String} link or undefined if no link found.
  linkUnderCursor (editor) {
    const cursorPosition = editor.getCursorBufferPosition()
    const link = this.linkAtPosition(editor, cursorPosition)
    if (link != null) return link

    // Look for a link to the left of the cursor
    if (cursorPosition.column > 0) {
      return this.linkAtPosition(editor, cursorPosition.translate([0, -1]))
    }
  },

  // Get the link at the buffer position in the editor.
  //
  // Returns a {String} link or undefined if no link found.
  linkAtPosition (editor, bufferPosition) {
    const token = editor.tokenForBufferPosition(bufferPosition)
    if (token && token.value && token.scopes.some(scope => LINK_SCOPE_REGEX.test(scope))) {
      return token.value
    }
  },

  // Get the link for the given name.
  //
  // This is for Markdown links of the style:
  //
  // ```
  // [label][name]
  //
  // [name]: https://github.com
  // ```
  //
  // Returns a {String} link
  linkForName (editor, linkName) {
    let link = linkName
    const regex = new RegExp(`^\\s*\\[${_.escapeRegExp(linkName)}\\]\\s*:\\s*(.+)$`, 'g')
    editor.backwardsScanInBufferRange(regex, [[0, 0], [Infinity, Infinity]], ({match, stop}) => {
      link = match[1]
      stop()
    })
    return link
  }
}
