/*
Copyright (C) 2017  Cloudbase Solutions SRL
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

// @flow

import React from 'react'
import styled from 'styled-components'
import { observer } from 'mobx-react'

import Switch from '../../atoms/Switch'
import TextInput from '../../atoms/TextInput'
import AutocompleteDropdown from '../../molecules/AutocompleteDropdown'
import Dropdown from '../../molecules/Dropdown'
import InfoIcon from '../../atoms/InfoIcon'
import PropertiesTable from '../../molecules/PropertiesTable'

import StyleProps from '../../styleUtils/StyleProps'
import LabelDictionary from '../../../utils/LabelDictionary'

import type { Field } from '../../../types/Field'

import asteriskImage from './images/asterisk.svg'

const getDirection = props => {
  if (props.type === 'strict-boolean' || props.type === 'boolean') {
    return 'row'
  }

  return 'column'
}
const Wrapper = styled.div`
  display: flex;
  flex-direction: ${props => getDirection(props)};
  ${props => getDirection(props) === 'row' ? '' : 'justify-content: center;'}
`
const Label = styled.div`
  font-weight: ${StyleProps.fontWeights.medium};
  margin-bottom: 8px;
  ${props => getDirection(props) === 'column' ? 'margin-bottom: 8px;' : ''}
`
const LabelText = styled.span`
  margin-right: ${props => props.noMargin ? 0 : 24}px;
`
const Asterisk = styled.div`
  ${StyleProps.exactSize('16px')}
  display: inline-block;
  background: url('${asteriskImage}') center no-repeat;
  margin-bottom: -3px;
  margin-left: ${props => props.marginLeft || '0px'};
`
type Props = {
  type: 'replica' | 'migration',
  name: string,
  value: any,
  onChange: (value: any) => void,
  valueCallback: (prop: Field, value: any) => void,
  className?: string,
  properties: Field[],
  enum: string[],
  required: boolean,
  width?: number,
  skipNullValue?: boolean,
  'data-test-id'?: string,
  style?: { [string]: mixed },
}
@observer
class WizardOptionsField extends React.Component<Props> {
  renderSwitch(propss: { triState: boolean }) {
    return (
      <Switch
        width="112px"
        justifyContent="flex-end"
        height={16}
        triState={propss.triState}
        checked={this.props.value}
        onChange={checked => { this.props.onChange(checked) }}
        style={{ marginTop: '-8px' }}
        leftLabel
        data-test-id="wOptionsField-switch"
      />
    )
  }

  renderTextInput() {
    return (
      <TextInput
        width={`${this.props.width || StyleProps.inputSizes.wizard.width}px`}
        value={this.props.value}
        onChange={e => { this.props.onChange(e.target.value) }}
        placeholder={LabelDictionary.get(this.props.name)}
        data-test-id="wOptionsField-textInput"
      />
    )
  }

  renderObjectTable() {
    if (!this.props.properties || !this.props.properties.length) {
      return null
    }

    return (
      <PropertiesTable
        properties={this.props.properties}
        valueCallback={this.props.valueCallback}
        onChange={this.props.onChange}
        data-test-id="wOptionsField-propertiesTable"
      />
    )
  }

  renderEnumDropdown() {
    const useDictionary = LabelDictionary.enumFields.find(f => f === this.props.name)
    let items = this.props.enum.map(e => {
      if (typeof e !== 'string' && e.separator === true) {
        return e
      }

      return {
        label: typeof e === 'string' ? (useDictionary ? LabelDictionary.get(e) : e) : e.name,
        value: typeof e === 'string' ? e : e.id,
      }
    })

    if (!this.props.skipNullValue) {
      items = [
        { label: 'Choose a value', value: null },
        ...items,
      ]
    }

    let selectedItem = items.find(i => i.value === this.props.value)

    if (items.length < 10) {
      return (
        <Dropdown
          data-test-id={`wOptionsField-enumDropdown-${this.props.name}`}
          width={this.props.width || StyleProps.inputSizes.wizard.width}
          noSelectionMessage="Choose a value"
          selectedItem={selectedItem}
          items={items}
          dimFirstItem
          onChange={item => this.props.onChange(item.value)}
        />
      )
    }

    return (
      <AutocompleteDropdown
        width={this.props.width || StyleProps.inputSizes.wizard.width}
        selectedItem={selectedItem}
        items={items}
        dimNullValue
        onChange={item => this.props.onChange(item.value)}
      />
    )
  }

  renderArrayDropdown() {
    let items = this.props.enum.map(e => {
      if (typeof e !== 'string' && e.separator === true) {
        return e
      }

      return {
        label: typeof e === 'string' ? LabelDictionary.get(e) : e.name,
        value: typeof e === 'string' ? e : e.id,
      }
    })
    let selectedItems = this.props.value || []
    return (
      <Dropdown
        multipleSelection
        items={items}
        selectedItems={selectedItems}
        width={this.props.width || StyleProps.inputSizes.wizard.width}
        noSelectionMessage="Choose values"
        onChange={item => this.props.onChange(item.value)}
      />
    )
  }

  renderField() {
    let field = null
    switch (this.props.type) {
      case 'strict-boolean':
        field = this.renderSwitch({ triState: false })
        break
      case 'boolean':
        field = this.renderSwitch({ triState: true })
        break
      case 'string':
        if (this.props.enum && this.props.enum.length) {
          field = this.renderEnumDropdown()
        } else {
          field = this.renderTextInput()
        }
        break
      case 'object':
        field = this.renderObjectTable()
        break
      case 'array':
        field = this.renderArrayDropdown()
        break
      default:
    }

    return field
  }

  renderLabel() {
    let description = LabelDictionary.getDescription(this.props.name)
    return (
      <Label>
        <LabelText data-test-id="wOptionsField-label" noMargin={!description && !this.props.required}>
          {LabelDictionary.get(this.props.name)}
        </LabelText>
        {description ? <InfoIcon text={description} marginLeft={-20} /> : null}
        {this.props.required ? <Asterisk data-test-id="wOptionsField-required" marginLeft={description ? '4px' : '-16px'} /> : null}
      </Label>
    )
  }

  render() {
    let field = this.renderField()

    if (!field) {
      return null
    }

    return (
      <Wrapper
        data-test-id={this.props['data-test-id'] || 'wOptionsField-wrapper'}
        type={this.props.type}
        className={this.props.className}
        style={this.props.style}
      >
        {this.renderLabel()}
        {field}
      </Wrapper>
    )
  }
}

export default WizardOptionsField
