import Link from 'app/components/links/link';
import {t} from 'app/locale';
import {Project} from 'app/types';
import {DisplayModes} from 'app/utils/discover/types';
import {tokenizeSearch} from 'app/utils/tokenizeSearch';
import {Incident, IncidentStats} from 'app/views/alerts/types';
import {getStartEndFromStats} from 'app/views/alerts/utils';
import {getIncidentDiscoverUrl} from 'app/views/alerts/utils/getIncidentDiscoverUrl';
import {transactionSummaryRouteWithQuery} from 'app/views/performance/transactionSummary/utils';

import {Dataset} from './types';

type PresetCta = {
  /**
   * The location to direct to upon clicking the CTA.
   */
  to: React.ComponentProps<typeof Link>['to'];
  /**
   * The CTA text
   */
  buttonText: string;
  /**
   * The tooltip title for the CTA button, may be empty.
   */
  title?: string;
};

type PresetCtaOpts = {
  orgSlug: string;
  projects: Project[];
  incident?: Incident;
  stats?: IncidentStats;
};

type Preset = {
  /**
   * The regex used to match aggregates to this preset.
   */
  match: RegExp;
  /**
   * The name of the preset
   */
  name: string;
  /**
   * The dataset that this preset applys to.
   */
  validDataset: Dataset[];
  /**
   * The default aggregate to use when selecting this preset
   */
  default: string;
  /**
   * Generates the CTA component
   */
  makeCtaParams: (opts: PresetCtaOpts) => PresetCta;
};

export const PRESET_AGGREGATES: Preset[] = [
  {
    name: t('Error count'),
    match: /^count\(\)/,
    validDataset: [Dataset.ERRORS],
    default: 'count()',
    /**
     * Simple "Open in Discover" button
     */
    makeCtaParams: makeDefaultCta,
  },
  {
    name: t('Users affected'),
    match: /^count_unique\(tags\[sentry:user\]\)/,
    validDataset: [Dataset.ERRORS],
    default: 'count_unique(tags[sentry:user])',
    /**
     * Simple "Open in Discover" button
     */
    makeCtaParams: makeDefaultCta,
  },
  {
    name: t('Latency'),
    match: /^(p[0-9]{2,3}|percentile\(transaction\.duration,[^)]+\)|avg\([^)]+\))/,
    validDataset: [Dataset.TRANSACTIONS],
    default: 'percentile(transaction.duration, 0.95)',
    /**
     * see: makeGenericTransactionCta
     */
    makeCtaParams: opts =>
      makeGenericTransactionCta({
        opts,
        tooltip: t('Latency by Transaction'),
      }),
  },
  {
    name: t('Apdex'),
    match: /^apdex\([0-9.]+\)/,
    validDataset: [Dataset.TRANSACTIONS],
    default: 'apdex(300)',
    /**
     * see: makeGenericTransactionCta
     */
    makeCtaParams: opts =>
      makeGenericTransactionCta({
        opts,
        tooltip: t('Apdex by Transaction'),
      }),
  },
  {
    name: t('Transaction Count'),
    match: /^count\(\)/,
    validDataset: [Dataset.TRANSACTIONS],
    default: 'count()',
    /**
     * see: makeGenericTransactionCta
     */
    makeCtaParams: opts => makeGenericTransactionCta({opts}),
  },
  {
    name: t('Failure rate'),
    match: /^failure_rate\(\)/,
    validDataset: [Dataset.TRANSACTIONS],
    default: 'failure_rate()',
    /**
     * See makeFailureRateCta
     */
    makeCtaParams: makeFailureRateCta,
  },
];

/**
 * - CASE 1: If has a specific transaction filter
 *   - CTA is: "View Transaction Summary"
 *   - Tooltip is the transaction name
 *   - the same period as the alert graph (i.e. with alert start time in the middle)
 *
 * - CASE 2: If transaction is NOT filtered, or has a * filter:
 *   - "Open in Discover" button with optional tooltip which opens a discover view with...
 *      - fields {transaction, count(), <metric>} sorted by count()
 *      - top-5 activated
 */
function makeGenericTransactionCta(opts: {
  opts: PresetCtaOpts;
  tooltip?: string;
}): PresetCta {
  const {
    opts: {orgSlug, projects, incident, stats},
    tooltip,
  } = opts;

  if (!incident || !stats) {
    return {to: '', buttonText: t('Incident details')};
  }

  const query = tokenizeSearch(incident.discoverQuery ?? '');
  const transaction = query
    .getTagValues('transaction')
    ?.find(filter => !filter.includes('*'));

  // CASE 1
  if (transaction !== undefined) {
    const period = getStartEndFromStats(stats);

    const summaryUrl = transactionSummaryRouteWithQuery({
      orgSlug,
      transaction,
      projectID: projects
        .filter(({slug}) => incident.projects.includes(slug))
        .map(({id}) => id),
      query: {...period},
    });

    return {
      to: summaryUrl,
      buttonText: t('View Transaction Summary'),
      title: transaction,
    };
  }

  // CASE 2
  const extraQueryParams = {
    fields: [...new Set(['transaction', 'count()', incident.alertRule.aggregate])],
    orderby: '-count',
    display: DisplayModes.TOP5,
  };

  const discoverUrl = getIncidentDiscoverUrl({
    orgSlug,
    projects,
    incident,
    stats,
    extraQueryParams,
  });

  return {
    to: discoverUrl,
    buttonText: t('Open in Discover'),
    title: tooltip,
  };
}

/**
 * - CASE 1: Filtered to a specific transaction, "Open in Discover" with...
 *   - fields [transaction.status, count()] sorted by count(),
 *   - "Top 5 period" activated.
 *
 * - CASE 2: If filtered on multiple transactions, "Open in Discover" button
 *   with tooltip "Failure rate by transaction" which opens a discover view
 *   - fields [transaction, failure_rate()] sorted by failure_rate
 *   - top 5 activated
 */
function makeFailureRateCta({orgSlug, incident, projects, stats}: PresetCtaOpts) {
  if (!incident || !stats) {
    return {to: '', buttonText: t('Incident details')};
  }

  const query = tokenizeSearch(incident.discoverQuery ?? '');
  const transaction = query
    .getTagValues('transaction')
    ?.find(filter => !filter.includes('*'));

  const extraQueryParams =
    transaction !== undefined
      ? // CASE 1
        {
          fields: ['transaction.status', 'count()'],
          orderby: '-count',
          display: DisplayModes.TOP5,
        }
      : // Case 2
        {
          fields: ['transaction', 'failure_rate()'],
          orderby: '-failure_rate',
          display: DisplayModes.TOP5,
        };

  const discoverUrl = getIncidentDiscoverUrl({
    orgSlug,
    projects,
    incident,
    stats,
    extraQueryParams,
  });

  return {
    to: discoverUrl,
    buttonText: t('Open in Discover'),
    title: transaction === undefined ? t('Failure rate by transaction') : undefined,
  };
}

/**
 * Get the CTA used for alerts that do not have a preset
 */
export function makeDefaultCta({
  orgSlug,
  projects,
  incident,
  stats,
}: PresetCtaOpts): PresetCta {
  if (!incident) {
    return {
      buttonText: t('Open in Discover'),
      to: '',
    };
  }

  const extraQueryParams = {
    display: DisplayModes.TOP5,
  };

  return {
    buttonText: t('Open in Discover'),
    to: getIncidentDiscoverUrl({orgSlug, projects, incident, stats, extraQueryParams}),
  };
}