import './site.scss';
import React from 'react';
import { connect } from 'react-redux';
import Input from './ui/Input';
import SearchForm from './form/SearchForm';
import KeymapsForm from './form/KeymapsForm';
import BlacklistForm from './form/BlacklistForm';
import PropertiesForm from './form/PropertiesForm';
import PartialBlacklistForm from './form/PartialBlacklistForm';
import * as settingActions from '../../settings/actions/setting';
import SettingData, {
  FormKeymaps, FormSearch, FormSettings, JSONTextSettings,
} from '../../shared/SettingData';
import { State as AppState } from '../reducers/setting';
import Properties from '../../shared/settings/Properties';
import Blacklist from '../../shared/settings/Blacklist';

const DO_YOU_WANT_TO_CONTINUE =
  'Some settings in JSON can be lost when migrating.  ' +
  'Do you want to continue?';

type StateProps = ReturnType<typeof mapStateToProps>;
interface DispatchProps {
  dispatch: (action: any) => void,
}
type Props = StateProps & DispatchProps & {
  // FIXME
  store: any;
};

class SettingsComponent extends React.Component<Props> {
  componentDidMount() {
    this.props.dispatch(settingActions.load());
  }

  renderFormFields(form: FormSettings) {
    return <div>
      <fieldset>
        <legend>Keybindings</legend>
        <KeymapsForm
          value={form.keymaps}
          onChange={this.bindKeymapsForm.bind(this)}
          onBlur={this.save.bind(this)}
        />
      </fieldset>
      <fieldset>
        <legend>Search Engines</legend>
        <SearchForm
          value={form.search}
          onChange={this.bindSearchForm.bind(this)}
          onBlur={this.save.bind(this)}
        />
      </fieldset>
      <fieldset>
        <legend>Blacklist</legend>
        <BlacklistForm
          value={form.blacklist}
          onChange={this.bindBlacklistForm.bind(this)}
          onBlur={this.save.bind(this)}
        />
      </fieldset>
      <fieldset>
        <legend>Partial blacklist</legend>
        <PartialBlacklistForm
          value={form.blacklist}
          onChange={this.bindBlacklistForm.bind(this)}
          onBlur={this.save.bind(this)}
        />
      </fieldset>
      <fieldset>
        <legend>Properties</legend>
        <PropertiesForm
          types={Properties.types()}
          value={form.properties.toJSON()}
          onChange={this.bindPropertiesForm.bind(this)}
          onBlur={this.save.bind(this)}
        />
      </fieldset>
    </div>;
  }

  renderJsonFields(json: JSONTextSettings, error: string) {
    return <div>
      <Input
        type='textarea'
        name='json'
        label='Plain JSON'
        spellCheck={false}
        error={error}
        onValueChange={this.bindJson.bind(this)}
        onBlur={this.save.bind(this)}
        value={json.toJSONText()}
      />
    </div>;
  }

  render() {
    let fields = null;
    const disabled = this.props.error.length > 0;
    if (this.props.source === 'form') {
      fields = this.renderFormFields(this.props.form!!);
    } else if (this.props.source === 'json') {
      fields = this.renderJsonFields(this.props.json!!, this.props.error);
    }
    return (
      <div>
        <h1>Configure Vim-Vixen</h1>
        <form className='vimvixen-settings-form'>
          <Input
            type='radio'
            id='setting-source-form'
            name='source'
            label='Use form'
            checked={this.props.source === 'form'}
            value='form'
            onValueChange={this.bindSource.bind(this)}
            disabled={disabled} />

          <Input
            type='radio'
            name='source'
            label='Use plain JSON'
            checked={this.props.source === 'json'}
            value='json'
            onValueChange={this.bindSource.bind(this)}
            disabled={disabled} />
          { fields }
        </form>
      </div>
    );
  }

  bindKeymapsForm(value: FormKeymaps) {
    const data = new SettingData({
      source: this.props.source,
      form: (this.props.form as FormSettings).buildWithKeymaps(value),
    });
    this.props.dispatch(settingActions.set(data));
  }

  bindSearchForm(value: any) {
    const data = new SettingData({
      source: this.props.source,
      form: (this.props.form as FormSettings).buildWithSearch(
        FormSearch.fromJSON(value)),
    });
    this.props.dispatch(settingActions.set(data));
  }

  bindBlacklistForm(blacklist: Blacklist) {
    const data = new SettingData({
      source: this.props.source,
      form: (this.props.form as FormSettings).buildWithBlacklist(blacklist),
    });
    this.props.dispatch(settingActions.set(data));
  }

  bindPropertiesForm(value: any) {
    const data = new SettingData({
      source: this.props.source,
      form: (this.props.form as FormSettings).buildWithProperties(
        Properties.fromJSON(value))
    });
    this.props.dispatch(settingActions.set(data));
  }

  bindJson(_name: string, value: string) {
    const data = new SettingData({
      source: this.props.source,
      json: JSONTextSettings.fromText(value),
    });
    this.props.dispatch(settingActions.set(data));
  }

  bindSource(_name: string, value: string) {
    const from = this.props.source;
    if (from === 'form' && value === 'json') {
      this.props.dispatch(settingActions.switchToJson(
        this.props.form as FormSettings));
      this.save();
    } else if (from === 'json' && value === 'form') {
      const b = window.confirm(DO_YOU_WANT_TO_CONTINUE);
      if (!b) {
        this.forceUpdate();
        return;
      }
      this.props.dispatch(
        settingActions.switchToForm(this.props.json as JSONTextSettings));
      this.save();
    }
  }

  save() {
    const { source, json, form } = this.props.store.getState();
    this.props.dispatch(settingActions.save(
      new SettingData({ source, json, form }),
    ));
  }
}

const mapStateToProps = (state: AppState) => ({ ...state });

export default connect(mapStateToProps)(SettingsComponent);