import React, { useEffect, useState } from 'react';
import { getDataSourceSrv } from '@grafana/runtime';
import { DataSourcePluginOptionsEditorProps, DataSourceSettings, SelectableValue } from '@grafana/data';
import { DataSourceHttpSettings, LegacyForms, Field, Input, Button, InlineFormLabel, Select } from '@grafana/ui';
const { FormField, Switch } = LegacyForms;
import { ZabbixDSOptions, ZabbixSecureJSONData } from '../types';

const SUPPORTED_SQL_DS = ['mysql', 'postgres', 'influxdb'];

export type Props = DataSourcePluginOptionsEditorProps<ZabbixDSOptions, ZabbixSecureJSONData>;
export const ConfigEditor = (props: Props) => {
  const { options, onOptionsChange } = props;

  const [selectedDBDatasource, setSelectedDBDatasource] = useState(null);
  const [currentDSType, setCurrentDSType] = useState('');

  // Apply some defaults on initial render
  useEffect(() => {
    const { jsonData, secureJsonFields } = options;

    // Set secureJsonFields.password to password and then remove it from config
    const { password, ...restJsonData } = jsonData;
    if (!secureJsonFields?.password) {
      if (!options.secureJsonData) {
        options.secureJsonData = {};
      }
      options.secureJsonData.password = password;
    }

    onOptionsChange({
      ...options,
      jsonData: {
        trends: true,
        trendsFrom: '',
        trendsRange: '',
        cacheTTL: '',
        ...restJsonData,
      },
    });

    if (options.jsonData.dbConnectionEnable) {
      if (!options.jsonData.dbConnectionDatasourceId) {
        const dsName = options.jsonData.dbConnectionDatasourceName;
        getDataSourceSrv().get(dsName)
        .then(ds => {
          if (ds) {
            const selectedDs = getDirectDBDatasources().find(dsOption => dsOption.id === ds.id);
            setSelectedDBDatasource({ label: selectedDs.name, value: selectedDs.id });
            setCurrentDSType(selectedDs.type);
            onOptionsChange({
              ...options,
              jsonData: {
                ...options.jsonData,
                dbConnectionDatasourceId: ds.id,
              },
            });
          }
        });
      } else {
        const selectedDs = getDirectDBDatasources().find(dsOption => dsOption.id === options.jsonData.dbConnectionDatasourceId);
        setSelectedDBDatasource({ label: selectedDs.name, value: selectedDs.id });
        setCurrentDSType(selectedDs.type);
      }
    }
  }, []);

  return (
    <>
      <DataSourceHttpSettings
        defaultUrl={'http://localhost/zabbix/api_jsonrpc.php'}
        dataSourceConfig={options}
        showAccessOptions={true}
        onChange={onOptionsChange}
      />

      <div className="gf-form-group">
        <h3 className="page-heading">Zabbix API details</h3>
        <div className="gf-form max-width-25">
          <FormField
            labelWidth={7}
            inputWidth={15}
            label="Username"
            value={options.jsonData.username || ''}
            onChange={jsonDataChangeHandler('username', options, onOptionsChange)}
            required
          />
        </div>
        <div className="gf-form max-width-25">
          {options.secureJsonFields?.password ?
            <>
              <FormField
                labelWidth={7}
                inputWidth={15}
                label="Password"
                disabled={true}
                value=""
                placeholder="Configured"
              />
              <Button onClick={resetSecureJsonField('password', options, onOptionsChange)}>Reset</Button>
            </>:
            <FormField
              labelWidth={7}
              inputWidth={15}
              label="Password"
              type="password"
              value={options.secureJsonData?.password || options.jsonData.password || ''}
              onChange={secureJsonDataChangeHandler('password', options, onOptionsChange)}
              required
            />
          }
        </div>
        <Switch
          label="Trends"
          labelClass="width-7"
          checked={options.jsonData.trends}
          onChange={jsonDataSwitchHandler('trends', options, onOptionsChange)}
        />
        {options.jsonData.trends &&
          <>
            <div className="gf-form">
              <FormField
                labelWidth={7}
                inputWidth={4}
                label="After"
                value={options.jsonData.trendsFrom || ''}
                placeholder="7d"
                onChange={jsonDataChangeHandler('trendsFrom', options, onOptionsChange)}
                tooltip="Time after which trends will be used.
                  Best practice is to set this value to your history storage period (7d, 30d, etc)."
              />
            </div>
            <div className="gf-form">
              <FormField
                labelWidth={7}
                inputWidth={4}
                label="Range"
                value={options.jsonData.trendsRange || ''}
                placeholder="4d"
                onChange={jsonDataChangeHandler('trendsRange', options, onOptionsChange)}
                tooltip="Time range width after which trends will be used instead of history.
                  It's better to set this value in range of 4 to 7 days to prevent loading large amount of history data."
              />
            </div>
          </>
        }
        <div className="gf-form">
          <FormField
            labelWidth={7}
            inputWidth={4}
            label="Cache TTL"
            value={options.jsonData.cacheTTL || ''}
            placeholder="1h"
            onChange={jsonDataChangeHandler('cacheTTL', options, onOptionsChange)}
            tooltip="Zabbix data source caches metric names in memory. Specify how often data will be updated."
          />
        </div>
      </div>

      <div className="gf-form-group">
        <h3 className="page-heading">Direct DB Connection</h3>
        <Switch
          label="Enable"
          labelClass="width-9"
          checked={options.jsonData.dbConnectionEnable}
          onChange={jsonDataSwitchHandler('dbConnectionEnable', options, onOptionsChange)}
        />
        {options.jsonData.dbConnectionEnable &&
          <>
            <div className="gf-form">
              <InlineFormLabel width={9}>Data Source</InlineFormLabel>
              <Select
                width={32}
                options={getDirectDBDSOptions()}
                value={selectedDBDatasource}
                onChange={directDBDatasourceChanegeHandler(options, onOptionsChange, setSelectedDBDatasource, setCurrentDSType)}
              />
            </div>
            {currentDSType === 'influxdb' &&
              <div className="gf-form">
                <FormField
                  labelWidth={9}
                  inputWidth={16}
                  label="Retention Policy"
                  value={options.jsonData.dbConnectionRetentionPolicy || ''}
                  placeholder="Retention policy name"
                  onChange={jsonDataChangeHandler('dbConnectionRetentionPolicy', options, onOptionsChange)}
                  tooltip="Specify retention policy name for fetching long-term stored data (optional).
                    Leave it blank if only default retention policy used."
                />
              </div>
            }
          </>
        }
      </div>

      <div className="gf-form-group">
        <h3 className="page-heading">Other</h3>
        <Switch
          label="Disable acknowledges for read-only users"
          labelClass="width-20"
          checked={options.jsonData.disableReadOnlyUsersAck}
          onChange={jsonDataSwitchHandler('disableReadOnlyUsersAck', options, onOptionsChange)}
        />
      </div>
    </>
  );
};

const jsonDataChangeHandler = (
  key: keyof ZabbixDSOptions,
  value: DataSourceSettings<ZabbixDSOptions, ZabbixSecureJSONData>,
  onChange: Props['onOptionsChange']
) => (
  event: React.SyntheticEvent<HTMLInputElement | HTMLSelectElement>
) => {
  onChange({
    ...value,
    jsonData: {
      ...value.jsonData,
      [key]: event.currentTarget.value,
    },
  });
};

const jsonDataSwitchHandler = (
  key: keyof ZabbixDSOptions,
  value: DataSourceSettings<ZabbixDSOptions, ZabbixSecureJSONData>,
  onChange: Props['onOptionsChange']
) => (
  event: React.SyntheticEvent<HTMLInputElement>
) => {
  onChange({
    ...value,
    jsonData: {
      ...value.jsonData,
      [key]: (event.target as HTMLInputElement).checked,
    },
  });
};

const secureJsonDataChangeHandler = (
  key: keyof ZabbixDSOptions,
  value: DataSourceSettings<ZabbixDSOptions, ZabbixSecureJSONData>,
  onChange: Props['onOptionsChange']
) => (
  event: React.SyntheticEvent<HTMLInputElement | HTMLSelectElement>
) => {
  onChange({
    ...value,
    secureJsonData: {
      ...value.secureJsonData,
      [key]: event.currentTarget.value,
    },
  });
};

const resetSecureJsonField = (
  key: keyof ZabbixDSOptions,
  value: DataSourceSettings<ZabbixDSOptions, ZabbixSecureJSONData>,
  onChange: Props['onOptionsChange']
) => (
  event: React.SyntheticEvent<HTMLButtonElement>
) => {
  onChange({
    ...value,
    secureJsonFields: {
      ...value.secureJsonFields,
      [key]: false,
    },
  });
};

const directDBDatasourceChanegeHandler = (
  options: DataSourceSettings<ZabbixDSOptions, ZabbixSecureJSONData>,
  onChange: Props['onOptionsChange'],
  setSelectedDS: React.Dispatch<any>,
  setSelectedDSType: React.Dispatch<any>,
) => (
  value: SelectableValue<number>
) => {
  const selectedDs = getDirectDBDatasources().find(dsOption => dsOption.id === value.value);
  setSelectedDS({ label: selectedDs.name, value: selectedDs.id });
  setSelectedDSType(selectedDs.type);
  onChange({
    ...options,
    jsonData: {
      ...options.jsonData,
      dbConnectionDatasourceId: value.value
    },
  });
};

const getDirectDBDatasources = () => {
  let dsList = (getDataSourceSrv() as any).getAll();
  dsList = dsList.filter(ds => SUPPORTED_SQL_DS.includes(ds.type));
  return dsList;
};

const getDirectDBDSOptions = () => {
  const dsList = getDirectDBDatasources();
  const dsOpts: Array<SelectableValue<number>> = dsList.map(ds => ({ label: ds.name, value: ds.id, description: ds.type }));
  return dsOpts;
};
