import React, { useEffect, useRef, useState } from 'react';

import { type SelectableValue } from '@grafana/data';
import { t } from '@grafana/i18n';
import { EditorField, EditorFieldGroup, EditorList, EditorRow } from '@grafana/plugin-ui';

import { type BuilderQueryEditorReduceExpression, BuilderQueryEditorReduceParameterTypes } from '../../dataquery.gen';
import { type AzureLogAnalyticsMetadataColumn } from '../../types/logAnalyticsMetadata';
import { type AzureMonitorQuery } from '../../types/query';

import AggregateItem from './AggregateItem';
import { type BuildAndUpdateOptions, isNumericColumn } from './utils';

interface AggregateSectionProps {
  query: AzureMonitorQuery;
  allColumns: AzureLogAnalyticsMetadataColumn[];
  templateVariableOptions: SelectableValue<string>;
  buildAndUpdateQuery: (options: Partial<BuildAndUpdateOptions>) => void;
}
export const AggregateSection: React.FC<AggregateSectionProps> = ({
  query,
  allColumns,
  buildAndUpdateQuery,
  templateVariableOptions,
}) => {
  const builderQuery = query.azureLogAnalytics?.builderQuery;
  const [aggregates, setAggregates] = useState<BuilderQueryEditorReduceExpression[]>(
    builderQuery?.reduce?.expressions || []
  );
  const prevTable = useRef<string | null>(builderQuery?.from?.property.name || null);
  const hasLoadedAggregates = useRef(false);

  useEffect(() => {
    const currentTable = builderQuery?.from?.property.name || null;

    if (prevTable.current !== currentTable || builderQuery?.reduce?.expressions.length === 0) {
      setAggregates([]);
      hasLoadedAggregates.current = false;
      prevTable.current = currentTable;
    }
  }, [builderQuery]);

  const availableColumns: Array<SelectableValue<string>> = builderQuery?.columns?.columns?.length
    ? builderQuery.columns.columns.map((col) => ({ label: col, value: col }))
    : allColumns.map((col) => ({ label: col.name, value: col.name }));
  const numericColumns: Array<SelectableValue<string>> = allColumns.filter(isNumericColumn).map((col) => ({
    label: col.name,
    value: col.name,
  }));

  const onChange = (newItems: Array<Partial<BuilderQueryEditorReduceExpression>>) => {
    setAggregates(newItems);

    buildAndUpdateQuery({
      reduce: newItems,
    });
  };

  const onDeleteAggregate = (aggregateToDelete: BuilderQueryEditorReduceExpression) => {
    setAggregates((prevAggregates) => {
      const updatedAggregates = prevAggregates.filter(
        (agg) =>
          agg.property?.name !== aggregateToDelete.property?.name || agg.reduce?.name !== aggregateToDelete.reduce?.name
      );

      buildAndUpdateQuery({
        reduce: updatedAggregates.length === 0 ? [] : updatedAggregates,
      });

      return updatedAggregates;
    });
  };

  return (
    <div data-testid="aggregate-section">
      <EditorRow>
        <EditorFieldGroup>
          <EditorField
            label={t('components.aggregate-section.label-aggregate', 'Aggregate')}
            optional={true}
            tooltip={t(
              'components.aggregate-section.tooltip-aggregate',
              'Perform calculations across rows of data, such as count, sum, average, minimum, maximum, standard deviation or percentiles.'
            )}
          >
            <EditorList
              items={aggregates}
              onChange={onChange}
              renderItem={makeRenderAggregate(
                availableColumns,
                numericColumns,
                onDeleteAggregate,
                templateVariableOptions
              )}
            />
          </EditorField>
        </EditorFieldGroup>
      </EditorRow>
    </div>
  );
};

function makeRenderAggregate(
  availableColumns: Array<SelectableValue<string>>,
  numericColumns: Array<SelectableValue<string>>,
  onDeleteAggregate: (aggregate: BuilderQueryEditorReduceExpression) => void,
  templateVariableOptions: SelectableValue<string>
) {
  return function renderAggregate(
    item: BuilderQueryEditorReduceExpression,
    onChange: (item: BuilderQueryEditorReduceExpression) => void
  ) {
    return (
      <AggregateItem
        aggregate={item}
        onChange={onChange}
        onDelete={() => onDeleteAggregate(item)}
        columns={
          item.reduce?.name && item.reduce.parameterType === BuilderQueryEditorReduceParameterTypes.Numeric
            ? numericColumns
            : availableColumns
        }
        templateVariableOptions={templateVariableOptions}
      />
    );
  };
}
