/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
import React from 'react';
import PropTypes from 'prop-types';
import { OverlayTrigger, Popover } from 'react-bootstrap';
import { t } from '@superset-ui/translation';

import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
import FormRow from '../../../components/FormRow';
import SelectControl from './SelectControl';
import CheckboxControl from './CheckboxControl';
import TextControl from './TextControl';
import { FILTER_CONFIG_ATTRIBUTES } from '../../constants';

const INTEGRAL_TYPES = new Set([
  'TINYINT',
  'SMALLINT',
  'INT',
  'INTEGER',
  'BIGINT',
  'LONG',
]);
const DECIMAL_TYPES = new Set([
  'FLOAT',
  'DOUBLE',
  'REAL',
  'NUMERIC',
  'DECIMAL',
  'MONEY',
]);

const propTypes = {
  datasource: PropTypes.object.isRequired,
  onChange: PropTypes.func,
  asc: PropTypes.bool,
  clearable: PropTypes.bool,
  multiple: PropTypes.bool,
  column: PropTypes.string,
  label: PropTypes.string,
  metric: PropTypes.string,
  searchAllOptions: PropTypes.bool,
  defaultValue: PropTypes.string,
};

const defaultProps = {
  onChange: () => {},
  asc: true,
  clearable: true,
  multiple: true,
  searchAllOptions: false,
};

const STYLE_WIDTH = { width: 350 };

export default class FilterBoxItemControl extends React.Component {
  constructor(props) {
    super(props);
    const {
      column,
      metric,
      asc,
      clearable,
      multiple,
      searchAllOptions,
      label,
      defaultValue,
    } = props;
    const state = {
      column,
      metric,
      label,
      asc,
      clearable,
      multiple,
      searchAllOptions,
      defaultValue,
    };
    this.state = state;
    this.onChange = this.onChange.bind(this);
    this.onControlChange = this.onControlChange.bind(this);
  }
  onChange() {
    this.props.onChange(this.state);
  }
  onControlChange(attr, value) {
    let typedValue = value;
    const { column: selectedColumnName, multiple } = this.state;
    if (value && !multiple && attr === FILTER_CONFIG_ATTRIBUTES.DEFAULT_VALUE) {
      // if single value filter_box,
      // convert input value string to the column's data type
      const { datasource } = this.props;
      const selectedColumn = datasource.columns.find(
        col => col.column_name === selectedColumnName,
      );

      if (selectedColumn && selectedColumn.type) {
        const type = selectedColumn.type.toUpperCase();
        if (type === 'BOOLEAN') {
          typedValue = value === 'true';
        } else if (INTEGRAL_TYPES.has(type)) {
          typedValue = isNaN(value) ? null : parseInt(value, 10);
        } else if (DECIMAL_TYPES.has(type)) {
          typedValue = isNaN(value) ? null : parseFloat(value);
        }
      }
    }
    this.setState({ [attr]: typedValue }, this.onChange);
  }
  setType() {}
  textSummary() {
    return this.state.column || 'N/A';
  }
  renderForm() {
    return (
      <div>
        <FormRow
          label={t('Column')}
          control={
            <SelectControl
              value={this.state.column}
              name="column"
              clearable={false}
              options={this.props.datasource.columns
                .filter(col => col !== this.state.column)
                .map(col => ({
                  value: col.column_name,
                  label: col.column_name,
                }))
                .concat([
                  { value: this.state.column, label: this.state.column },
                ])}
              onChange={v => this.onControlChange('column', v)}
            />
          }
        />
        <FormRow
          label={t('Label')}
          control={
            <TextControl
              value={this.state.label}
              name="label"
              onChange={v => this.onControlChange('label', v)}
            />
          }
        />
        <FormRow
          label={t('Default')}
          tooltip={t(
            '(optional) default value for the filter, when using ' +
              'the multiple option, you can use a semicolon-delimited list ' +
              'of options.',
          )}
          control={
            <TextControl
              value={this.state.defaultValue}
              name="defaultValue"
              onChange={v =>
                this.onControlChange(FILTER_CONFIG_ATTRIBUTES.DEFAULT_VALUE, v)
              }
            />
          }
        />
        <FormRow
          label={t('Sort Metric')}
          tooltip={t('Metric to sort the results by')}
          control={
            <SelectControl
              value={this.state.metric}
              name="column"
              options={this.props.datasource.metrics
                .filter(metric => metric !== this.state.metric)
                .map(m => ({
                  value: m.metric_name,
                  label: m.metric_name,
                }))
                .concat([
                  { value: this.state.metric, label: this.state.metric },
                ])}
              onChange={v => this.onControlChange('metric', v)}
            />
          }
        />
        <FormRow
          label={t('Sort Ascending')}
          tooltip={t('Check for sorting ascending')}
          isCheckbox
          control={
            <CheckboxControl
              value={this.state.asc}
              onChange={v => this.onControlChange('asc', v)}
            />
          }
        />
        <FormRow
          label={t('Allow Multiple Selections')}
          isCheckbox
          tooltip={t(
            'Multiple selections allowed, otherwise filter ' +
              'is limited to a single value',
          )}
          control={
            <CheckboxControl
              value={this.state.multiple}
              onChange={v =>
                this.onControlChange(FILTER_CONFIG_ATTRIBUTES.MULTIPLE, v)
              }
            />
          }
        />
        <FormRow
          label={t('Search All Filter Options')}
          tooltip={t(
            'By default, each filter loads at most 1000 choices at the initial page load. ' +
              'Check this box if you have more than 1000 filter values and want to enable dynamically ' +
              'searching that loads filter values as users type (may add stress to your database).',
          )}
          isCheckbox
          control={
            <CheckboxControl
              value={this.state.searchAllOptions}
              onChange={v =>
                this.onControlChange(
                  FILTER_CONFIG_ATTRIBUTES.SEARCH_ALL_OPTIONS,
                  v,
                )
              }
            />
          }
        />
        <FormRow
          label={t('Required')}
          tooltip={t('User must select a value for this filter')}
          isCheckbox
          control={
            <CheckboxControl
              value={!this.state.clearable}
              onChange={v => this.onControlChange('clearable', !v)}
            />
          }
        />
      </div>
    );
  }
  renderPopover() {
    return (
      <Popover id="ts-col-popo" title={t('Filter Configuration')}>
        <div style={STYLE_WIDTH}>{this.renderForm()}</div>
      </Popover>
    );
  }
  render() {
    return (
      <span>
        {this.textSummary()}{' '}
        <OverlayTrigger
          container={document.body}
          trigger="click"
          rootClose
          ref="trigger"
          placement="right"
          overlay={this.renderPopover()}
        >
          <InfoTooltipWithTrigger
            icon="edit"
            className="text-primary"
            label="edit-ts-column"
          />
        </OverlayTrigger>
      </span>
    );
  }
}

FilterBoxItemControl.propTypes = propTypes;
FilterBoxItemControl.defaultProps = defaultProps;
