import type {PageFilters} from 'sentry/types/core';
import type {Organization} from 'sentry/types/organization';
import {defined} from 'sentry/utils';
import {
  getAggregateAlias,
  isAggregateFieldOrEquation,
} from 'sentry/utils/discover/fields';
import {decodeBoolean, decodeList, decodeScalar} from 'sentry/utils/queryString';
import {DisplayType, type Widget} from 'sentry/views/dashboards/types';
import {
  eventViewFromWidget,
  getFieldsFromEquations,
  getWidgetInterval,
} from 'sentry/views/dashboards/utils';
import {Mode} from 'sentry/views/explore/contexts/pageParamsContext/mode';
import {getExploreUrl} from 'sentry/views/explore/utils';
import {ChartType} from 'sentry/views/insights/common/components/chart';

export function getWidgetExploreUrl(
  widget: Widget,
  selection: PageFilters,
  organization: Organization
) {
  const eventView = eventViewFromWidget(widget.title, widget.queries[0]!, selection);
  const {query: locationQueryParams} = eventView.getResultsViewUrlTarget(
    organization.slug,
    false,
    undefined
  );

  // Pull a max of 3 valid Y-Axis from the widget
  const yAxisOptions = eventView.getYAxisOptions().map(({value}) => value);
  locationQueryParams.yAxes = [
    ...new Set(
      widget.queries[0]!.aggregates.filter(aggregate => yAxisOptions.includes(aggregate))
    ),
  ].slice(0, 3);

  // Visualization specific transforms
  let exploreMode: Mode | undefined = undefined;
  let chartType: ChartType = ChartType.LINE;
  switch (widget.displayType) {
    case DisplayType.BAR:
      exploreMode = Mode.AGGREGATE;
      chartType = ChartType.BAR;
      break;
    case DisplayType.LINE:
      exploreMode = Mode.AGGREGATE;
      chartType = ChartType.LINE;
      break;
    case DisplayType.AREA:
      exploreMode = Mode.AGGREGATE;
      chartType = ChartType.AREA;
      break;
    case DisplayType.TABLE:
    case DisplayType.BIG_NUMBER:
      exploreMode = Mode.SAMPLES;
      break;
    default:
      break;
  }

  // Equation fields need to have their terms explicitly selected as columns in the discover table
  const fields =
    Array.isArray(locationQueryParams.field) || !defined(locationQueryParams.field)
      ? locationQueryParams.field
      : [locationQueryParams.field];

  const query = widget.queries[0]!;
  const queryFields = defined(query.fields)
    ? query.fields
    : [...query.columns, ...query.aggregates];

  // Updates fields by adding any individual terms from equation fields as a column
  getFieldsFromEquations(queryFields).forEach(term => {
    if (Array.isArray(fields) && !fields.includes(term)) {
      fields.unshift(term);
    }
  });
  locationQueryParams.field = fields;

  const datetime = {
    end: decodeScalar(locationQueryParams.end) ?? null,
    period: decodeScalar(locationQueryParams.statsPeriod) ?? null,
    start: decodeScalar(locationQueryParams.start) ?? null,
    utc: decodeBoolean(locationQueryParams.utc) ?? null,
  };

  const queryParams = {
    // Page filters should propagate
    selection: {
      ...selection,
      datetime,
    },
    orgSlug: organization.slug,
    mode: exploreMode,
    visualize: [
      {
        chartType,
        yAxes: locationQueryParams.yAxes,
      },
    ],
    groupBy: fields?.filter(field => !isAggregateFieldOrEquation(field)),
    field: decodeList(locationQueryParams.field),
    query: decodeScalar(locationQueryParams.query),
    sort:
      defined(fields) && defined(locationQueryParams.sort)
        ? _getSort(fields, locationQueryParams.sort as string)
        : undefined,
    interval:
      decodeScalar(locationQueryParams.interval) ??
      getWidgetInterval(widget.displayType, selection.datetime),
  };

  return getExploreUrl(queryParams);
}

function _getSort(fields: string[], sort: string) {
  const descending = sort.startsWith('-');
  const rawSort = descending ? sort.slice(1) : sort;
  const sortedField = fields?.find(field => getAggregateAlias(field) === rawSort);
  return descending ? `-${sortedField}` : sortedField;
}
