React = require 'react'
_ = require 'lodash'
owasp = require 'owasp-password-strength-test'

TextInput = React.createFactory(require './text_input')

{ENTER} = require '../constants/keyboard'

{div, li, h4, ul, span} = React.DOM

MIN_PASSWORD_LENGTH = 6
MAX_PASSWORD_LENGTH = 15
REMOVED_REQUIREMENTS = [2, 6]


PasswordInput = React.createClass

  displayName: 'PasswordInput'

  propTypes:
    onChange: React.PropTypes.func

  getInitialState: ->
    owasp.config
      minLength: MIN_PASSWORD_LENGTH
      maxLength: MAX_PASSWORD_LENGTH
      isPassphrase: false

    test = owasp.test('')

    return {
      passwordTest: test
      passwordRequirements: @buildTestRequirements(test)
      currentPassword: null
      confirmPassword: null
    }

  getDefaultProps: ->
    onChange: ->

  isValid: ->
    current = @refs.input.getValue()
    confirm = @refs.inputConfirm.getValue() if @refs.inputConfirm?
    return confirm?.length and confirm is current and @state.passwordTest.failedTests.length is 0

  render: ->
    {isNewUser, resetPass, focusOnMount} = @props
    {passwordTest, currentPassword, confirmPassword, passwordRequirements} = @state
    passwordsMatch = currentPassword is confirmPassword
    passwordFailures = passwordTest.failedTests
    passwordErrors = passwordTest.errors
    passingTest = passwordFailures?.length is 0

    # remove certain tests for our purposes
    if passwordFailures and passwordFailures.length is 0 then passingTest = true

    inputProps =
      placeholder: t 'Password'
      ref: 'input'
      key: 'input'
      type: 'password'

    inputProps = _.assign(inputProps, @props)
    inputProps.onChange = @testCurrentPassword

    
    div {
      className: 'password-form'
    }, [
      TextInput(inputProps)
      TextInput {
        key: 'inputConfirm'
        ref: 'inputConfirm'
        type: 'password'
        autoComplete: @props.autoComplete
        tabIndex: @props.tabIndex
        placeholder: t 'Confirm Password'
        onChange: @testConfirmPassword
        wrapperClass: 'confirm'
        value: confirmPassword
        onKeyUp: @handleKeyUp
      } if (not isNewUser or resetPass) and passingTest
      div {
        key: 'requirements'
        className: 'requirements'
      }, [
        h4 {
          key: 'pass-req-header'
          className: 'header'
        }, "#{t('Password requirements')}:"
        ul {
          key: 'pass-reqs'
          className: 'password-reqs'
        }, passwordRequirements
        div({
          key: 'pass-match'
        }, [
            span { 
              key: 'match-icon'
              className: "icon-status #{if passwordsMatch then 'success' else 'error'}" 
            }, null 
            span {
              key: 'match-text'
              className: 'req-text'
            }, t('Passwords match')
          ]
        ) if passingTest
      ]
    ]

  componentDidMount: ->
    if @props.focusOnMount then @refs.input.focus()

  getValue: ->
    unless @refs.inputConfirm? then ''
    else @refs.inputConfirm.getValue()

  handleKeyUp: (e) ->
    return unless e.keyCode is ENTER
    
    @props.handleKeyUp?() if @isValid()

  buildTestRequirements: (test) ->
    failedTestErrors =
      0: t("At least __minLength__ characters", { minLength: MIN_PASSWORD_LENGTH })
      3: t("At least __count__ lowercase letter", { count: 1 })
      4: t("At least __count__ uppercase letter", { count: 1 })
      5: t("At least __count__ number", { count: 1 })

    passwordRequirements = []
    {failedTests, errors} = test

    # Remove specified requirements
    for req in REMOVED_REQUIREMENTS
      index = failedTests?.indexOf(req)
      if index > -1 then failedTests.splice(index, 1)
      if index > -1 then errors.splice(index, 1)

    # Display the remaining tests
    for key, val of failedTestErrors
      status = if failedTests.indexOf(+key) > -1 then 'error' else 'success'

      passwordRequirements.push(
        li {
          key: key
          className: 'req-item'
        }, [
          span {
            key: 'status'
            className: "icon-status #{status}"
          }, null
          span {
            key: 'val'
            className: 'req-text'
          }, val
        ]
      )

    return passwordRequirements

  testCurrentPassword: (e) ->
    value = @refs.input.getValue()
    test = owasp.test(value)

    @setState { 
      passwordTest: test
      currentPassword: value
      passwordRequirements: @buildTestRequirements(test)
    }

  testConfirmPassword: (e) ->
    value = @refs.inputConfirm.getValue()

    @setState
      confirmPassword: value
    , ->
      @props.onChange()



module.exports = PasswordInput