const createTorrent = require('create-torrent')
const path = require('path')
const prettyBytes = require('prettier-bytes')
const React = require('react')

const { dispatch, dispatcher } = require('../lib/dispatcher')

const FlatButton = require('material-ui/FlatButton').default
const RaisedButton = require('material-ui/RaisedButton').default
const TextField = require('material-ui/TextField').default
const Checkbox = require('material-ui/Checkbox').default

const CreateTorrentErrorPage = require('../components/create-torrent-error-page')
const Heading = require('../components/heading')
const ShowMore = require('../components/show-more')

// Shows a basic UI to create a torrent, from an already-selected file or folder.
// Includes a "Show Advanced..." button and more advanced UI.
class CreateTorrentPage extends React.Component {
  constructor (props) {
    super(props)

    const state = this.props.state
    const info = state.location.current()

    // First, extract the base folder that the files are all in
    let pathPrefix = info.folderPath
    if (!pathPrefix) {
      pathPrefix = info.files.map((x) => x.path).reduce(findCommonPrefix)
      if (!pathPrefix.endsWith('/') && !pathPrefix.endsWith('\\')) {
        pathPrefix = path.dirname(pathPrefix)
      }
    }

    // Then, exclude .DS_Store and other dotfiles
    const files = info.files
      .filter((f) => !containsDots(f.path, pathPrefix))
      .map((f) => ({ name: f.name, path: f.path, size: f.size }))
    if (files.length === 0) return (<CreateTorrentErrorPage state={state} />)

    // Then, use the name of the base folder (or sole file, for a single file torrent)
    // as the default name. Show all files relative to the base folder.
    let defaultName, basePath
    if (files.length === 1) {
      // Single file torrent: /a/b/foo.jpg -> torrent name 'foo.jpg', path '/a/b'
      defaultName = files[0].name
      basePath = pathPrefix
    } else {
      // Multi file torrent: /a/b/{foo, bar}.jpg -> torrent name 'b', path '/a'
      defaultName = path.basename(pathPrefix)
      basePath = path.dirname(pathPrefix)
    }

    // Default trackers
    const trackers = createTorrent.announceList.join('\n')

    this.state = {
      comment: '',
      isPrivate: false,
      pathPrefix,
      basePath,
      defaultName,
      files,
      trackers
    }

    // Create React event handlers only once
    this.handleSetIsPrivate = (_, isPrivate) => this.setState({ isPrivate })
    this.handleSetComment = (_, comment) => this.setState({ comment })
    this.handleSetTrackers = (_, trackers) => this.setState({ trackers })
    this.handleSubmit = handleSubmit.bind(this)
  }

  render () {
    const files = this.state.files

    // Sanity check: show the number of files and total size
    const numFiles = files.length
    const totalBytes = files
      .map((f) => f.size)
      .reduce((a, b) => a + b, 0)
    const torrentInfo = `${numFiles} files, ${prettyBytes(totalBytes)}`

    return (
      <div className='create-torrent'>
        <Heading level={1}>Create torrent {this.state.defaultName}</Heading>
        <div className='torrent-info'>{torrentInfo}</div>
        <div className='torrent-attribute'>
          <label>Path:</label>
          <div>{this.state.pathPrefix}</div>
        </div>
        <ShowMore
          style={{
            marginBottom: 10
          }}
          hideLabel='Hide advanced settings...'
          showLabel='Show advanced settings...'
        >
          {this.renderAdvanced()}
        </ShowMore>
        <div className='float-right'>
          <FlatButton
            className='control cancel'
            label='Cancel'
            style={{
              marginRight: 10
            }}
            onClick={dispatcher('cancel')}
          />
          <RaisedButton
            className='control create-torrent-button'
            label='Create Torrent'
            primary
            onClick={this.handleSubmit}
          />
        </div>
      </div>
    )
  }

  // Renders everything after clicking Show Advanced...:
  // * Is Private? (private torrents, not announced to DHT)
  // * Announce list (trackers)
  // * Comment
  renderAdvanced () {
    // Create file list
    const maxFileElems = 100
    const files = this.state.files
    const fileElems = files.slice(0, maxFileElems).map((file, i) => {
      const relativePath = path.relative(this.state.pathPrefix, file.path)
      return (<div key={i}>{relativePath}</div>)
    })
    if (files.length > maxFileElems) {
      fileElems.push(<div key='more'>+ {files.length - maxFileElems} more</div>)
    }

    // Align the text fields
    const textFieldStyle = { width: '' }
    const textareaStyle = { margin: 0 }

    return (
      <div key='advanced' className='create-torrent-advanced'>
        <div key='private' className='torrent-attribute'>
          <label>Private:</label>
          <Checkbox
            className='torrent-is-private control'
            style={{ display: '' }}
            checked={this.state.isPrivate}
            onCheck={this.handleSetIsPrivate}
          />
        </div>
        <div key='trackers' className='torrent-attribute'>
          <label>Trackers:</label>
          <TextField
            className='torrent-trackers control'
            style={textFieldStyle}
            textareaStyle={textareaStyle}
            multiLine
            rows={2}
            rowsMax={10}
            value={this.state.trackers}
            onChange={this.handleSetTrackers}
          />
        </div>
        <div key='comment' className='torrent-attribute'>
          <label>Comment:</label>
          <TextField
            className='torrent-comment control'
            style={textFieldStyle}
            textareaStyle={textareaStyle}
            hintText='Optionally describe your torrent...'
            multiLine
            rows={2}
            rowsMax={10}
            value={this.state.comment}
            onChange={this.handleSetComment}
          />
        </div>
        <div key='files' className='torrent-attribute'>
          <label>Files:</label>
          <div>{fileElems}</div>
        </div>
      </div>
    )
  }
}

function handleSubmit () {
  const announceList = this.state.trackers
    .split('\n')
    .map((s) => s.trim())
    .filter((s) => s !== '')
  const options = {
    // We can't let the user choose their own name if we want WebTorrent
    // to use the files in place rather than creating a new folder.
    name: this.state.defaultName,
    path: this.state.basePath,
    files: this.state.files,
    announce: announceList,
    comment: this.state.comment.trim()
  }

  // If torrent is not private, leave private flag unset. This ensures that
  // the torrent info hash will match the result generated by other tools,
  // including webtorrent-cli.
  if (this.state.isPrivate) options.private = true

  dispatch('createTorrent', options)
}

// Finds the longest common prefix
function findCommonPrefix (a, b) {
  let i
  for (i = 0; i < a.length && i < b.length; i++) {
    if (a.charCodeAt(i) !== b.charCodeAt(i)) break
  }
  if (i === a.length) return a
  if (i === b.length) return b
  return a.substring(0, i)
}

function containsDots (path, pathPrefix) {
  const suffix = path.substring(pathPrefix.length).replace(/\\/g, '/')
  return ('/' + suffix).includes('/.')
}

module.exports = CreateTorrentPage
