import { PanelMenuItem } from '@grafana/data';
import { PromQuery } from '@grafana/prometheus';
import { getDataSourceSrv } from '@grafana/runtime';
import { SceneTimeRangeLike, VizPanel } from '@grafana/scenes';
import { DataQuery, DataSourceRef } from '@grafana/schema';
import { getQueryRunnerFor } from 'app/features/dashboard-scene/utils/utils';

import { DashboardScene } from '../../dashboard-scene/scene/DashboardScene';
import { MetricScene } from '../MetricScene';
import { reportExploreMetrics } from '../interactions';

import { DataTrailEmbedded, DataTrailEmbeddedState } from './DataTrailEmbedded';
import { SceneDrawerAsScene } from './SceneDrawer';
import { QueryMetric, getQueryMetrics } from './getQueryMetrics';
import { createAdHocFilters, getQueryMetricLabel, getTimeRangeFromDashboard } from './utils';

export async function addDataTrailPanelAction(dashboard: DashboardScene, panel: VizPanel, items: PanelMenuItem[]) {
  if (panel.state.pluginId !== 'timeseries') {
    return;
  }

  const queryRunner = getQueryRunnerFor(panel);
  if (queryRunner == null) {
    return;
  }

  const { queries, datasource, data } = queryRunner.state;

  if (datasource == null) {
    return;
  }

  if (datasource.type !== 'prometheus') {
    return;
  }

  const dataSourceApi = await getDataSourceSrv().get(datasource);

  if (dataSourceApi.interpolateVariablesInQueries == null) {
    return;
  }

  const interpolated = dataSourceApi
    .interpolateVariablesInQueries(queries, { __sceneObject: { value: panel } }, data?.request?.filters)
    .filter(isPromQuery);

  const queryMetrics = getQueryMetrics(interpolated.map((q) => q.expr));

  const subMenu: PanelMenuItem[] = queryMetrics.map((item) => {
    return {
      text: getQueryMetricLabel(item),
      onClick: createClickHandler(item, dashboard, dataSourceApi),
    };
  });

  if (subMenu.length > 0) {
    items.push({
      text: 'Explore metrics',
      iconClassName: 'code-branch',
      subMenu: getUnique(subMenu),
    });
  }
}

function getUnique<T extends { text: string }>(items: T[]) {
  const uniqueMenuTexts = new Set<string>();
  function isUnique({ text }: { text: string }) {
    const before = uniqueMenuTexts.size;
    uniqueMenuTexts.add(text);
    const after = uniqueMenuTexts.size;
    return after > before;
  }
  return items.filter(isUnique);
}

function getEmbeddedTrailsState(
  { metric, labelFilters, query }: QueryMetric,
  timeRange: SceneTimeRangeLike,
  dataSourceUid: string | undefined
) {
  const state: DataTrailEmbeddedState = {
    metric,
    filters: createAdHocFilters(labelFilters),
    dataSourceUid,
    timeRange,
  };

  return state;
}

function createCommonEmbeddedTrailStateProps(item: QueryMetric, dashboard: DashboardScene, ds: DataSourceRef) {
  const timeRange = getTimeRangeFromDashboard(dashboard);
  const trailState = getEmbeddedTrailsState(item, timeRange, ds.uid);
  const embeddedTrail: DataTrailEmbedded = new DataTrailEmbedded(trailState);

  embeddedTrail.trail.addActivationHandler(() => {
    if (embeddedTrail.trail.state.topScene instanceof MetricScene) {
      embeddedTrail.trail.state.topScene.setActionView('breakdown');
    }
  });

  const commonProps = {
    scene: embeddedTrail,
    title: 'Explore metrics',
  };

  return commonProps;
}

function createClickHandler(item: QueryMetric, dashboard: DashboardScene, ds: DataSourceRef) {
  return () => {
    const commonProps = createCommonEmbeddedTrailStateProps(item, dashboard, ds);
    const drawerScene = new SceneDrawerAsScene({
      ...commonProps,
      onDismiss: () => dashboard.closeModal(),
    });
    reportExploreMetrics('exploration_started', { cause: 'dashboard_panel' });
    dashboard.showModal(drawerScene);
  };
}

export function isPromQuery(model: DataQuery): model is PromQuery {
  return 'expr' in model;
}
