import { useCallback, useMemo } from 'react';

import { type SelectableValue, type StandardEditorContext } from '@grafana/data';
import { t } from '@grafana/i18n';
import { InlineFieldRow, InlineField, RadioButtonGroup, Select } from '@grafana/ui';
import { NumberInput } from 'app/core/components/OptionsUI/NumberInput';

import { type Options, type MapViewConfig } from '../panelcfg.gen';
import { type GeomapInstanceState } from '../types';

type Props = {
  labelWidth: number;
  value: MapViewConfig;
  onChange: (value?: MapViewConfig | undefined) => void;
  context: StandardEditorContext<Options, GeomapInstanceState>;
};

// Data scope options for 'Fit to data'
enum DataScopeValues {
  all = 'all',
  layer = 'layer',
  last = 'last',
}
enum DataScopeLabels {
  all = 'All layers',
  layer = 'Layer',
  last = 'Last value',
}

const ScopeOptions = Object.values(DataScopeValues);

const DataScopeOptions: Array<SelectableValue<DataScopeValues>> = ScopeOptions.map((dataScopeOption) => ({
  label: DataScopeLabels[dataScopeOption],
  value: dataScopeOption,
}));

export const FitMapViewEditor = ({ labelWidth, value, onChange, context }: Props) => {
  const layers = useMemo(() => {
    if (context.options?.layers) {
      return context.options.layers.map((layer) => ({
        label: layer.name,
        value: layer.name,
        description: undefined,
      }));
    }
    return [];
  }, [context.options?.layers]);

  const onSelectLayer = useCallback(
    (selection: SelectableValue<string>) => {
      onChange({ ...value, layer: selection.value });
    },
    [value, onChange]
  );

  const allLayersEditorFragment = (
    <InlineFieldRow>
      <InlineField
        label={t('geomap.fit-map-view-editor.all-layers-editor-fragment.label-layer', 'Layer')}
        labelWidth={labelWidth}
        grow={true}
      >
        <Select options={layers} onChange={onSelectLayer} placeholder={layers[0]?.label} value={value.layer} />
      </InlineField>
    </InlineFieldRow>
  );

  const onChangePadding = (padding: number | undefined) => {
    onChange({ ...value, padding: padding });
  };

  const lastOnlyEditorFragment = (
    <InlineFieldRow>
      <InlineField
        label={t('geomap.fit-map-view-editor.last-only-editor-fragment.label-padding', 'Padding')}
        labelWidth={labelWidth}
        grow={true}
        tooltip={t(
          'geomap.fit-map-view-editor.last-only-editor-fragment.tooltip-padding-relative-percent-beyond-extent',
          'Sets padding in relative percent beyond data extent'
        )}
      >
        <NumberInput value={value?.padding ?? 5} min={0} step={1} onChange={onChangePadding} />
      </InlineField>
    </InlineFieldRow>
  );

  const currentDataScope = value.allLayers
    ? DataScopeValues.all
    : !value.allLayers && value.lastOnly
      ? DataScopeValues.last
      : DataScopeValues.layer;

  const onDataScopeChange = (dataScope: DataScopeValues) => {
    if (dataScope !== DataScopeValues.all && !value.layer) {
      onChange({
        ...value,
        allLayers: dataScope === String(DataScopeValues.all),
        lastOnly: dataScope === String(DataScopeValues.last),
        layer: layers[0].value,
      });
    } else {
      onChange({
        ...value,
        allLayers: dataScope === String(DataScopeValues.all),
        lastOnly: dataScope === String(DataScopeValues.last),
      });
    }
  };

  return (
    <>
      <InlineFieldRow>
        <InlineField label={t('geomap.fit-map-view-editor.label-data', 'Data')} labelWidth={labelWidth} grow={true}>
          <RadioButtonGroup
            value={currentDataScope}
            options={DataScopeOptions}
            onChange={onDataScopeChange}
          ></RadioButtonGroup>
        </InlineField>
      </InlineFieldRow>
      {!value?.allLayers && allLayersEditorFragment}
      {!value?.lastOnly && lastOnlyEditorFragment}
    </>
  );
};
