import * as React from 'react';
import * as _ from 'lodash';
import { Label, Form } from 'semantic-ui-react';
const { Flex, Box } = require('reflexbox');
import {
  Input,
  Dropdown,
  Image,
  Modal,
  Button,
} from 'semantic-ui-react';

class LexInputContainer extends React.Component<any, any> {
  public render() {
    return (
      <div>
        <Form>
          <Form.Group as={Flex} inline={true} style={{ margin: '0 0 5px 5px' }}>
            <Form.Field as={Box} w={2 / 5} style={{ textAlign: 'right' }}>
              {this.props.label}
            </Form.Field>
            <Form.Field as={Box} w={3 / 5} >
              {this.props.children}
            </Form.Field>
          </Form.Group>
        </Form>
      </div>
    );
  }
}

function changedLabel(changed: boolean, text: string) {
  let labelClass = changed ? 'olive' : '';
  return (
    <Label
      pointing="right"
      className={labelClass}
    >
      {text}
    </Label>
  );
}

function textInput(params: any) {
  let { field, sh, value, changed } = params;
  return (
    <LexInputContainer
      label={changedLabel(changed, field)}
      key={field}
    >
      <Input
        onChange={(e, d) => { sh(d.value); }}
        value={value}
        placeholder={field}
        type="text"
        dir="auto"
        style={{ width: '10em' }}
      />
    </LexInputContainer>
  );
}

function selectInput(params: any) {
  let { field, sh, value, options, langSelOpts, changed } = params;
  let staticOpts = options;
  let fieldOpts = _.get<any>(langSelOpts, field, []);
  let selOpts = staticOpts ? staticOpts : fieldOpts;
  let dropOptions = selOpts.map((k: any, i: any, c: any) => {
    return { key: i, value: k, text: k };
  });
  return (
    <LexInputContainer key={field} label={changedLabel(changed, field)}>
      <Dropdown
        options={dropOptions}
        onChange={(e, d) => { sh(d.value); }}
        value={value}
        compact={true}
        selection={true}
        search={true}
        style={{ width: '10em' }}
      />
    </LexInputContainer>
  );
}

function imagePreview(params: any) {
  let { field, value, changed } = params;
  let imageSrc = '/png/' + value;
  return value !== '' ? (
    <LexInputContainer key={field} label={changedLabel(changed, field)}>
      <Image src={imageSrc} size="large" bordered={true} />
    </LexInputContainer>
  ) : textInput(params);
}

function listInput(params: any) {
  let { field, sh, langSelOpts, value, changed } = params;
  let fieldOpts = _.get<any>(langSelOpts, field, []);
  let renderLabel = (label: any) => ({
    content: `${label.value}`,
  });
  let dropOptions = fieldOpts.map((k: any, i: any, c: any) => {
    return {
      key: i,
      value: k,
      text: k,
    };
  });
  return (
    <LexInputContainer key={field} label={changedLabel(changed, field)}>
      <Dropdown
        options={dropOptions}
        onChange={(e, d) => {
          sh(d.value);
        }}
        value={value}
        compact={true}
        selection={true}
        search={true}
        multiple={true}
        fluid={true}
        style={{ width: '10em' }}
        renderLabel={renderLabel}
      />
    </LexInputContainer>
  );
}

function propListInput(params: any) {
  let { field, changed } = params;
  return (
    <LexInputContainer key={field} label={changedLabel(changed, field)}>
      <PropListInput params={params} />
    </LexInputContainer>
  );
}

class PropListInput extends React.Component<any, any> {
  constructor(props: any) {
    super(props);
    this.state = { modalOpen: false, exKey: '', exVal: '' };
  }

  dropOptsForVal(value: any) {
    let { field, langSelOpts } = this.props.params;
    let fieldOpts = _.get<any>(langSelOpts, field, []);
    function valueForKey(key: string) {
      let match = _.find(value, (v: any) => _.isEqual(v.key, key));
      if (match) {
        return match;
      } else {
        return { key, value: '' };
      }
    }
    return fieldOpts.map((k: any, i: any) => {
      return {
        key: i,
        value: valueForKey(k),
        text: k,
      };
    });
  }

  public render() {
    let { sh, value } = this.props.params;
    let dropOptions = this.dropOptsForVal(value);
    let renderLabel = (label: any) => ({
      content: `${label.value.key}-${label.value.value}`,
    });
    let onCloseModal = (e: any) => {
      let except = { key: this.state.exKey, value: this.state.exVal };
      let ns = _.concat(value, except);
      this.setState({
        modalOpen: false,
        exKey: '',
        exVal: ''
      });
      sh(ns);
    };
    let dropDownComp = (
      <Dropdown
        options={dropOptions}
        onChange={(e, d) => {
          let newValue = d.value as any;
          let addedValue = _.difference(newValue, value) as any;
          let didAdd = _.size(addedValue) > 0;
          let exKey = didAdd ? addedValue[0].key : '';
          this.setState({ exKey, modalOpen: didAdd });
          if (!didAdd) {
            sh(newValue);
          }
        }}
        value={value}
        compact={true}
        selection={true}
        search={true}
        multiple={true}
        fluid={true}
        style={{ width: '10em' }}
        renderLabel={renderLabel}
      />
    );
    return (
      <Modal
        open={this.state.modalOpen}
        onClose={onCloseModal}
        size="mini"
        trigger={dropDownComp}
      >
        <Modal.Content>
          Enter the exception for {this.state.exKey}
        </Modal.Content>
        <Modal.Actions>
          <Input
            focus={true}
            onChange={(e, d: any) => {
              this.setState({ exVal: d.value });
            }}
          />
          <Button onClick={onCloseModal}>
            Done
              </Button>
        </Modal.Actions>
      </Modal>
    );
  }
}

export function componentForType(type: string, params: any) {
  switch (type) {
    case 'text': {
      return textInput(params);
    }
    case 'select': {
      return selectInput(params);
    }
    case 'preview': {
      return imagePreview(params);
    }
    case 'list': {
      return listInput(params);
    }
    case 'proplist': {
      return propListInput(params);
    }
    default: {
      console.log('type discarded :', type);
      return null;
    }
  }
}
