import React from 'react';
import { Dialog, ReactWidget } from '@jupyterlab/apputils';
import { IDatasourceForm, textDatasource } from './api/datasource';
import { Widget } from '@lumino/widgets';
import { Input, message, Select } from 'antd';

interface IProps {
  value: Partial<IDatasourceForm>;
  error: keyof IDatasourceForm | null;
  onChange: (v: Partial<IDatasourceForm>) => void;
  onConnection: (v: Partial<IDatasourceForm>) => void;
}

const DatasourceForm: React.FunctionComponent<IProps> = ({
  value,
  error,
  onChange,
  onConnection
}) => {
  return (
    <form className="jldbq-form">
      <label className={error === 'datasource' ? 'jldbq-form-error' : ''}>
        <span className="jldbq-form-label">数据源类型:</span>
        <Select
          className="jldbq-form-select"
          placeholder="请选择数据源类型"
          onChange={(val: any) => onChange({ datasource: val })}
        >
          <Select.Option value="mysql">MySQL</Select.Option>
          <Select.Option value="hive">Hive</Select.Option>
        </Select>
      </label>
      <label className={error === 'datasource_name' ? 'jldbq-form-error' : ''}>
        <span className="jldbq-form-label">数据源名称:</span>
        <Input
          className="jldbq-form-input"
          placeholder="请输入数据源名称"
          value={value.datasource_name || ''}
          onChange={evt => onChange({ datasource_name: evt.target.value })}
        />
      </label>
      <label className={error === 'jdbc_url' ? 'jldbq-form-error' : ''}>
        <span className="jldbq-form-label">数据库地址:</span>
        <Input
          className="jldbq-form-input"
          placeholder="示例：host:port"
          value={value.jdbc_url || ''}
          onChange={evt => onChange({ jdbc_url: evt.target.value })}
        />
      </label>
      <label className={error === 'database_name' ? 'jldbq-form-error' : ''}>
        <span className="jldbq-form-label">数据库名称:</span>
        <Input
          className="jldbq-form-input"
          placeholder={
            value.datasource === 'hive' ? '选填' : '请输入数据库名称'
          }
          value={value.database_name || ''}
          onChange={evt => onChange({ database_name: evt.target.value })}
        />
      </label>
      <label className={error === 'jdbc_username' ? 'jldbq-form-error' : ''}>
        <span className="jldbq-form-label">用户名:</span>
        <Input
          className="jldbq-form-input"
          placeholder="请输入用户名"
          value={value.jdbc_username || ''}
          onChange={evt => onChange({ jdbc_username: evt.target.value })}
        />
      </label>

      <label className={error === 'jdbc_password' ? 'jldbq-form-error' : ''}>
        <span className="jldbq-form-label">密码:</span>
        <Input.Password
          className="jldbq-form-input"
          placeholder="请输入密码"
          value={value.jdbc_password || ''}
          onChange={evt => onChange({ jdbc_password: evt.target.value })}
        />
      </label>
      <div className="jldbq-form-link">
        <span onClick={() => onConnection(value)}>测试连接</span>
      </div>
    </form>
  );
};

export class DatasourceFormDialogBody
  extends ReactWidget
  implements Dialog.IBodyWidget<IDatasourceForm> {
  constructor(manager: string, options?: Widget.IOptions) {
    super(options);
    // this._manager = manager;
  }
  render(): JSX.Element {
    return (
      <DatasourceForm
        value={this._datasourceItem}
        error={this._error}
        onChange={v => {
          this._datasourceItem = { ...this._datasourceItem, ...v };
          this._error = null;
          this.update();
        }}
        onConnection={async v => {
          const res = await textDatasource({ ...v } as IDatasourceForm);
          if (res && res !== 'error') {
            void message.success('测试成功');
          } else {
            void message.error('测试失败');
          }
        }}
      />
    );
  }

  getValue(): IDatasourceForm {
    const {
      jdbc_url,
      jdbc_username,
      jdbc_password,
      database_name,
      datasource_name,
      datasource
    } = this._datasourceItem;
    if (!datasource) {
      this._setError('datasource');
    }
    if (!datasource_name) {
      this._setError('datasource_name');
    }
    if (!jdbc_url || !validateIpAndPort(jdbc_url)) {
      this._setError('jdbc_url');
    }
    if (!database_name && datasource === 'mysql') {
      this._setError('database_name');
    }
    if (!jdbc_username) {
      this._setError('jdbc_username');
    }
    if (!jdbc_password) {
      this._setError('jdbc_password');
    }
    return {
      jdbc_url,
      jdbc_username,
      jdbc_password,
      database_name: database_name as any,
      datasource_name,
      datasource
      // manager: this._manager
    };
  }

  private _setError(error: keyof IDatasourceForm): never {
    this._error = error;
    this.update();
    void message.error(error);
    throw new Error(error);
  }

  private _datasourceItem: Partial<IDatasourceForm> = {};
  private _error: IProps['error'] = null;
  // private _manager: string;
}

function validateIpAndPort(input: string): boolean {
  const parts = input.split(':');
  if (parts.length > 2) {
    return false;
  }
  const ip = parts[0].split('.');
  if (
    ip.length !== 4 ||
    !ip.every(function (segment) {
      return validateNum(segment, 0, 255);
    })
  ) {
    return false;
  }
  const port = parts[1];
  if (port && !validateNum(port, 1, 65535)) {
    return false;
  }
  return true;
}

function validateNum(input: string, min: number, max: number): boolean {
  const num = +input;
  return num >= min && num <= max && input === num.toString();
}
