import {Fragment} from 'react';
import {useTheme} from '@emotion/react';
import styled from '@emotion/styled';
import {Location} from 'history';

import {BarChart, BarChartProps} from 'sentry/components/charts/barChart';
import BarChartZoom from 'sentry/components/charts/barChartZoom';
import ErrorPanel from 'sentry/components/charts/errorPanel';
import {HeaderTitleLegend} from 'sentry/components/charts/styles';
import TransparentLoadingMask from 'sentry/components/charts/transparentLoadingMask';
import Placeholder from 'sentry/components/placeholder';
import QuestionTooltip from 'sentry/components/questionTooltip';
import {IconWarning} from 'sentry/icons/iconWarning';
import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import {Organization} from 'sentry/types';
import {Series} from 'sentry/types/echarts';
import EventView from 'sentry/utils/discover/eventView';
import {formatAbbreviatedNumber} from 'sentry/utils/formatters';
import getDynamicText from 'sentry/utils/getDynamicText';
import HistogramQuery from 'sentry/utils/performance/histogram/histogramQuery';
import {HistogramData} from 'sentry/utils/performance/histogram/types';
import {
  computeBuckets,
  formatHistogramData,
} from 'sentry/utils/performance/histogram/utils';

import {DoubleHeaderContainer} from '../../styles';
import {getFieldOrBackup} from '../display/utils';

const NUM_BUCKETS = 50;
const PRECISION = 0;

type Props = {
  eventView: EventView;
  field: string;
  location: Location;
  onFilterChange: (minValue: number, maxValue: number) => void;
  organization: Organization;
  title: string;
  titleTooltip: string;
  usingBackupAxis: boolean;
  backupField?: string;
  didReceiveMultiAxis?: (axisCounts: Record<string, number>) => void;
};

export function HistogramChart(props: Props) {
  const {
    location,
    onFilterChange,
    organization,
    eventView,
    field,
    title,
    titleTooltip,
    didReceiveMultiAxis,
    backupField,
    usingBackupAxis,
  } = props;

  const _backupField = backupField ? [backupField] : [];

  return (
    <div>
      <DoubleHeaderContainer>
        <HeaderTitleLegend>
          {title}
          <QuestionTooltip position="top" size="sm" title={titleTooltip} />
        </HeaderTitleLegend>
      </DoubleHeaderContainer>
      <HistogramQuery
        location={location}
        orgSlug={organization.slug}
        eventView={eventView}
        numBuckets={NUM_BUCKETS}
        precision={PRECISION}
        fields={[field, ..._backupField]}
        dataFilter="exclude_outliers"
        didReceiveMultiAxis={didReceiveMultiAxis}
      >
        {results => {
          const _field = usingBackupAxis ? getFieldOrBackup(field, backupField) : field;
          const isLoading = results.isLoading;
          const isErrored = results.error !== null;
          const chartData = results.histograms?.[_field];

          if (isErrored) {
            return (
              <ErrorPanel height="250px">
                <IconWarning color="gray300" size="lg" />
              </ErrorPanel>
            );
          }

          if (!chartData) {
            return null;
          }

          return (
            <Chart
              isLoading={isLoading}
              isErrored={isErrored}
              chartData={chartData}
              location={location}
              onFilterChange={onFilterChange}
              field={_field}
            />
          );
        }}
      </HistogramQuery>
    </div>
  );
}

type ChartProps = {
  field: string;
  isErrored: boolean;
  isLoading: boolean;
  location: Location;
  onFilterChange: Props['onFilterChange'];
  chartData?: HistogramData;
  colors?: string[];
  disableChartPadding?: boolean;
  disableXAxis?: boolean;
  disableZoom?: boolean;
  grid?: BarChartProps['grid'];
  height?: number;
};

export function Chart(props: ChartProps) {
  const {
    isLoading,
    isErrored,
    chartData,
    location,
    field,
    onFilterChange,
    height,
    grid,
    disableXAxis,
    disableZoom,
    disableChartPadding,
    colors,
  } = props;
  const theme = useTheme();

  if (!chartData) {
    return null;
  }

  const series = {
    seriesName: t('Count'),
    data: formatHistogramData(chartData, {type: 'duration'}),
  };

  const xAxis = {
    type: 'category' as const,
    truncate: true,
    axisTick: {
      alignWithLabel: true,
    },
  };

  const allSeries: Series[] = [];

  if (!isLoading && !isErrored) {
    allSeries.push(series);
  }

  const yAxis = {
    type: 'value' as const,
    axisLabel: {
      color: theme.chartLabel,
      formatter: (value: number | string) => formatAbbreviatedNumber(value),
    },
  };

  return (
    <Fragment>
      <BarChartZoom
        minZoomWidth={10 ** -PRECISION * NUM_BUCKETS}
        location={location}
        paramStart={`${field}:>=`}
        paramEnd={`${field}:<=`}
        xAxisIndex={[0]}
        buckets={computeBuckets(chartData)}
        onHistoryPush={onFilterChange}
      >
        {zoomRenderProps => {
          return (
            <BarChartContainer hasPadding={!disableChartPadding}>
              <MaskContainer>
                <TransparentLoadingMask visible={isLoading} />
                {getDynamicText({
                  value: (
                    <BarChart
                      height={height ?? 250}
                      series={allSeries}
                      xAxis={disableXAxis ? {show: false} : xAxis}
                      yAxis={yAxis}
                      colors={colors}
                      grid={
                        grid ?? {
                          left: space(3),
                          right: space(3),
                          top: space(3),
                          bottom: isLoading ? space(4) : space(1.5),
                        }
                      }
                      stacked
                      {...(disableZoom ? {} : zoomRenderProps)}
                    />
                  ),
                  fixed: <Placeholder height="250px" testId="skeleton-ui" />,
                })}
              </MaskContainer>
            </BarChartContainer>
          );
        }}
      </BarChartZoom>
    </Fragment>
  );
}

const BarChartContainer = styled('div')<{hasPadding?: boolean}>`
  padding-top: ${p => (p.hasPadding ? space(1) : 0)};
  position: relative;
`;

const MaskContainer = styled('div')`
  position: relative;
`;

export default HistogramChart;
