import {Location, LocationDescriptor} from 'history';

import {getParams} from 'app/components/organizations/globalSelectionHeader/getParams';
import {ALL_ACCESS_PROJECTS} from 'app/constants/globalSelectionHeader';
import {OrganizationSummary} from 'app/types';
import {Event} from 'app/types/event';
import {defined} from 'app/utils';
import EventView from 'app/utils/discover/eventView';
import {eventDetailsRouteWithEventView, generateEventSlug} from 'app/utils/discover/urls';
import {
  EventLite,
  QuickTraceEvent,
  TraceError,
} from 'app/utils/performance/quickTrace/types';
import {getTraceTimeRangeFromEvent} from 'app/utils/performance/quickTrace/utils';
import {QueryResults} from 'app/utils/tokenizeSearch';
import {getTraceDetailsUrl} from 'app/views/performance/traceDetails/utils';
import {getTransactionDetailsUrl} from 'app/views/performance/utils';

export function isQuickTraceEvent(
  event: QuickTraceEvent | TraceError
): event is QuickTraceEvent {
  return defined((event as QuickTraceEvent)['transaction.duration']);
}

export type ErrorDestination = 'discover' | 'issue';

export type TransactionDestination = 'discover' | 'performance';

export function generateIssueEventTarget(
  event: TraceError,
  organization: OrganizationSummary
): LocationDescriptor {
  return `/organizations/${organization.slug}/issues/${event.issue_id}/events/${event.event_id}`;
}

function generatePerformanceEventTarget(
  event: EventLite,
  organization: OrganizationSummary,
  location: Location
): LocationDescriptor {
  const eventSlug = generateEventSlug({
    id: event.event_id,
    project: event.project_slug,
  });
  return getTransactionDetailsUrl(
    organization,
    eventSlug,
    event.transaction,
    location.query
  );
}

function generateDiscoverEventTarget(
  event: EventLite | TraceError,
  organization: OrganizationSummary,
  location: Location
): LocationDescriptor {
  const eventSlug = generateEventSlug({
    id: event.event_id,
    project: event.project_slug,
  });
  return eventDetailsRouteWithEventView({
    orgSlug: organization.slug,
    eventSlug,
    eventView: EventView.fromLocation(location),
  });
}

export function generateSingleErrorTarget(
  event: TraceError,
  organization: OrganizationSummary,
  location: Location,
  destination: ErrorDestination
): LocationDescriptor {
  switch (destination) {
    case 'issue':
      return generateIssueEventTarget(event, organization);
    case 'discover':
    default:
      return generateDiscoverEventTarget(event, organization, location);
  }
}

export function generateSingleTransactionTarget(
  event: EventLite,
  organization: OrganizationSummary,
  location: Location,
  destination: TransactionDestination
): LocationDescriptor {
  switch (destination) {
    case 'performance':
      return generatePerformanceEventTarget(event, organization, location);
    case 'discover':
    default:
      return generateDiscoverEventTarget(event, organization, location);
  }
}

export function generateMultiTransactionsTarget(
  currentEvent: Event,
  events: EventLite[],
  organization: OrganizationSummary,
  groupType: 'Ancestor' | 'Children' | 'Descendant'
): LocationDescriptor {
  const queryResults = new QueryResults([]);
  const eventIds = events.map(child => child.event_id);
  for (let i = 0; i < eventIds.length; i++) {
    queryResults.addOp(i === 0 ? '(' : 'OR');
    queryResults.addQuery(`id:${eventIds[i]}`);
    if (i === eventIds.length - 1) {
      queryResults.addOp(')');
    }
  }

  const {start, end} = getTraceTimeRangeFromEvent(currentEvent);
  const traceEventView = EventView.fromSavedQuery({
    id: undefined,
    name: `${groupType} Transactions of Event ID ${currentEvent.id}`,
    fields: ['transaction', 'project', 'trace.span', 'transaction.duration', 'timestamp'],
    orderby: '-timestamp',
    query: queryResults.formatString(),
    projects: [...new Set(events.map(child => child.project_id))],
    version: 2,
    start,
    end,
  });
  return traceEventView.getResultsViewUrlTarget(organization.slug);
}

export function generateTraceTarget(
  event: Event,
  organization: OrganizationSummary
): LocationDescriptor {
  const traceId = event.contexts?.trace?.trace_id ?? '';

  const dateSelection = getParams(getTraceTimeRangeFromEvent(event));

  if (organization.features.includes('performance-view')) {
    // TODO(txiao): Should this persist the current query when going to trace view?
    return getTraceDetailsUrl(organization, traceId, dateSelection, {});
  }

  const eventView = EventView.fromSavedQuery({
    id: undefined,
    name: `Events with Trace ID ${traceId}`,
    fields: ['title', 'event.type', 'project', 'trace.span', 'timestamp'],
    orderby: '-timestamp',
    query: `trace:${traceId}`,
    projects: organization.features.includes('global-views')
      ? [ALL_ACCESS_PROJECTS]
      : [Number(event.projectID)],
    version: 2,
    ...dateSelection,
  });
  return eventView.getResultsViewUrlTarget(organization.slug);
}
