/** @jsx StatsUI.dom */
import $ from 'jquery'

import {StatsUI} from './ui'

class Hook {

  constructor (statsState) {
    this.statsState = statsState
  }

  hook (elem, hook) {

  }

  open (state) {
    this.statsState.setState(state, ['pagination'])
  }

}

class LogWrapper {
  constructor (log) {
    this.data = log
  }

  // TODO: Next refactoring should implement appURL and accountURL methods server side, get them from the response.
  appURL () {
    return `/buyers/applications/${this.data.app.id}`
  }

  accountURL () {
    return `/buyers/accounts/${this.data.app.account.id}`
  }

  codeClass () {
    let code = this.data.code.toString()

    switch (code) {
      case this._match(code, /^2\d\d/):
        return 'success'
      case this._match(code, /^4\d\d/):
        return 'client-error'
      case this._match(code, /^5\d\d/):
        return 'server-error'
      default:
        return 'unknown'
    }
  }

  request () {
    return this.data.request
  }

  response () {
    return this.data.response
  }

  timestamp () {
    return this.data.timestamp
  }

  _match (code, regex) {
    let result = code.match(regex)
    if (result) return result[0]
  }
}

export class StatsLogsUI extends StatsUI {
  constructor ({statsState, source, container}) {
    super({statsState, container})
    this.source = source
    this.data = []
  }

  template () {
    let logs = this.data.logs.map((log) => { return new LogWrapper(log) })

    if (logs.length > 0) {
      return (
        <div id='results_list' className='StatsLogs'>
          <table className='data'>
            <thead>
            <tr>
              <th>Response Code</th>
              <th>Time</th>
              <th>Developer Account</th>
              <th>Application</th>
            </tr>
            </thead>
            <tbody className='log-requests'>
            {
              logs.map(log =>
                [
                  <tr>
                    <td>
                      <a href='#' className={`show-trace-lr ${log.codeClass()}`}>
                        {log.data.code}<span className='elipsis'>…</span>
                      </a>
                    </td>
                    <td>{log.timestamp()}</td>
                    <td><a href={log.accountURL()}>{log.data.app.account.org_name}</a></td>
                    <td><a href={log.appURL()}>{log.data.app.name}</a></td>
                  </tr>,
                  <tr className='tras-detail' style={{display: 'none'}}>
                    <td colSpan='6'>
                      <dl>
                        <dt>Reported usage by metric:</dt>
                        <dd className='usage'>{log.data.usage}</dd>
                        <dt>Request:</dt>
                        <dd>
                          <pre className='traces request'>
                            {log.request()}
                          </pre>
                        </dd>
                        <dt>Response:</dt>
                        <dd>
                          <pre className={`traces status-code ${log.codeClass()}`}>
                            {log.response()}
                          </pre>
                        </dd>
                      </dl>
                    </td>
                  </tr>
                ]
              )
            }
            </tbody>
          </table>

          {this.paginate()}

        </div>
      )
    } else {
      return (
        <div className='StatsMessages'>
          <h3>There are no requests in the log.</h3>
        </div>
      )
    }
  }

  render () {
    this._addLoadingMessage()
    this.update(this.statsState.state, () => { super.render() })
  }

  refresh () {
    this.update(this.statsState.state, () => { super.refresh() })
  }

  update (state, callback) {
    let logsUI = this
    this._displayLoading(true)
    this._getLogs(state).then((result) => {
      logsUI.data = result
      logsUI._displayLoading(false)
      callback()
    })
  }

  paginate () {
    let pagination = this.data.pagination
    let state = this.statsState.state
    let currentPage = +pagination.page || 1
    let nextPageState = Object.assign({}, state, {pagination: {page: currentPage + 1}})
    let prevPageState = Object.assign({}, state, {pagination: {page: currentPage - 1}})
    let totalPages = Math.ceil(pagination.total / pagination.per_page)
    let pages = []
    let lastPages = []
    let firstPages = []
    let nextPage
    let prevPage
    const gap = <span className='StatsLogs-pagination-item gap'>...</span>

    let paginateHook = new Hook(this.statsState)

    for (let i = 1, page, pageState; i <= totalPages; i++) {
      pageState = Object.assign({}, state, {pagination: {page: i}})
      if (i === currentPage) {
        page = <em className='StatsLogs-pagination-item current'>{`${i}`}</em>
      } else {
        page = <a className='StatsLogs-pagination-link StatsLogs-pagination-item'
                  onclick={ev => { ev.preventDefault(); paginateHook.open(pageState) }}>{`${i}`}</a>
      }
      pages.push(page)
    }

    if (currentPage < pages.length) {
      nextPage = <a className='StatsLogs-pagination-link StatsLogs-pagination-item'
                    onclick={ev => { ev.preventDefault(); paginateHook.open(nextPageState) }}>Next →</a>
    }
    if (currentPage > 1) {
      prevPage = <a className='StatsLogs-pagination-link StatsLogs-pagination-item'
                    onclick={ev => { ev.preventDefault(); paginateHook.open(prevPageState) }}> {'← Previous'}</a>
    }
    if (currentPage < pages.length - 4) {
      lastPages = [gap, ...pages.slice(-4, -1)]
    }
    if (currentPage > 3) {
      firstPages = pages.slice(currentPage - 2, currentPage + 3)
    } else {
      firstPages = pages.slice(0, 4)
    }

    return (
      <div className='StatsLogs-pagination pagination'>
        {(() => {
          if (pages.length > 10) {
            return [prevPage, ...firstPages, ...lastPages, nextPage]
          } else {
            return [prevPage, ...pages, nextPage]
          }
        })()}
      </div>

    )
  }

  _getLogs (state) {
    // TODO: next refactor API backend should return empty response when code is empty
    if ('code' in state && state.code.length > 0) {
      return this.source.logRequests(state)
    } else {
      let emptyResponse = {
        logs: [ ],
        pagination: {
          total: 1,
          page: '1',
          per_page: 20
        }
      }
      return new Promise((resolve, reject) => resolve(emptyResponse))
    }
  }

  _addLoadingMessage () {
    $(this.container).append('<div class="StatsLogs-loading">Loading...</div>')
  }

  _displayLoading (isLoading) {
    let $logs = $(this.container).find('.StatsLogs')
    let $message = $(this.container).find('.StatsLogs-loading')

    $logs.toggleClass('is-hidden', isLoading)
    $message.toggleClass('is-hidden', !isLoading)
  }
}
