import { css } from '@emotion/css';

import {
  CoreApp,
  FieldType,
  getPanelDataSummary,
  GrafanaTheme2,
  PanelData,
  PanelDataSummary,
  PanelPluginVisualizationSuggestion,
  store,
} from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { t, Trans } from '@grafana/i18n';
import { PanelDataErrorViewProps, locationService, config } from '@grafana/runtime';
import { VizPanel } from '@grafana/scenes';
import { Icon, usePanelContext, useStyles2 } from '@grafana/ui';
import { CardButton } from 'app/core/components/CardButton';
import { LS_VISUALIZATION_SELECT_TAB_KEY } from 'app/core/constants';
import { toggleVizPicker } from 'app/features/dashboard/components/PanelEditor/state/reducers';
import { VisualizationSelectPaneTab } from 'app/features/dashboard/components/PanelEditor/types';
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene';
import { findVizPanelByKey, getVizPanelKeyForPanelId } from 'app/features/dashboard-scene/utils/utils';
import { useDispatch } from 'app/types/store';

import { changePanelPlugin } from '../state/actions';
import { hasData } from '../suggestions/utils';

function hasNoQueryConfigured(data: PanelData): boolean {
  return !data.request?.targets || data.request.targets.length === 0;
}

export function PanelDataErrorView(props: PanelDataErrorViewProps) {
  const styles = useStyles2(getStyles);
  const context = usePanelContext();
  const dataSummary = getPanelDataSummary(props.data.series);
  const dispatch = useDispatch();

  const dashboardScene: DashboardScene | undefined = window.__grafanaSceneContext;
  let panel;
  if (dashboardScene instanceof DashboardScene) {
    panel = findVizPanelByKey(dashboardScene, getVizPanelKeyForPanelId(props.panelId));
  } else {
    panel = getDashboardSrv().getCurrent()?.getPanelById(props.panelId);
  }

  const openVizPicker = () => {
    store.setObject(LS_VISUALIZATION_SELECT_TAB_KEY, VisualizationSelectPaneTab.Suggestions);
    if (dashboardScene) {
      dashboardScene.state.editPanel?.state.optionsPane?.onToggleVizPicker();

      return;
    }

    dispatch(toggleVizPicker(true));
  };

  const switchToTable = () => {
    if (!panel) {
      return;
    }

    if (panel instanceof VizPanel) {
      panel.changePluginType('table');

      return;
    }

    dispatch(
      changePanelPlugin({
        panel,
        pluginId: 'table',
      })
    );
  };

  const loadSuggestion = (s: PanelPluginVisualizationSuggestion) => {
    if (!panel) {
      return;
    }

    if (panel instanceof VizPanel) {
      panel.changePluginType(s.pluginId, s.options, s.fieldConfig);
    } else {
      dispatch(
        changePanelPlugin({
          ...s, // includes panelId, config, etc
          panel,
        })
      );
    }

    if (s.transformations) {
      setTimeout(() => {
        locationService.partial({ tab: 'transform' });
      }, 100);
    }
  };

  const noData = !hasData(props.data);
  const noQueryConfigured = hasNoQueryConfigured(props.data);
  const showEmptyState = Boolean(
    config.featureToggles.newVizSuggestions && context.app === CoreApp.PanelEditor && noQueryConfigured && noData
  );
  const message = getMessageFor(props, dataSummary, showEmptyState);

  return (
    <div className={styles.wrapper}>
      {showEmptyState && <Icon name="chart-line" size="xxxl" className={styles.emptyStateIcon} />}
      <div className={styles.message} data-testid={selectors.components.Panels.Panel.PanelDataErrorMessage}>
        {message}
      </div>
      {context.app === CoreApp.PanelEditor && dataSummary.hasData && panel && (
        <div className={styles.actions}>
          {props.suggestions && (
            <>
              {props.suggestions.map((v) => (
                <CardButton key={v.name} icon="process" onClick={() => loadSuggestion(v)}>
                  {v.name}
                </CardButton>
              ))}
            </>
          )}
          <CardButton icon="table" onClick={switchToTable}>
            <Trans i18nKey="panel.panel-data-error-view.switch-to-table">Switch to table</Trans>
          </CardButton>
          <CardButton icon="chart-line" onClick={openVizPicker}>
            <Trans i18nKey="panel.panel-data-error-view.open-visualization-suggestions">
              Open visualization suggestions
            </Trans>
          </CardButton>
        </div>
      )}
    </div>
  );
}

function getMessageFor(
  { data, fieldConfig, message, needsNumberField, needsTimeField, needsStringField }: PanelDataErrorViewProps,
  dataSummary: PanelDataSummary,
  showEmptyState: boolean
): string {
  if (message) {
    return message;
  }

  const noData = !hasData(data);

  if (showEmptyState) {
    return t(
      'dashboard.new-panel.empty-state-message',
      'Run a query to visualize it here or go to all visualizations to add other panel types'
    );
  }

  if (noData) {
    return fieldConfig?.defaults.noValue ?? t('panel.panel-data-error-view.no-value.default', 'No data');
  }

  if (needsStringField && !dataSummary.hasFieldType(FieldType.string)) {
    return t('panel.panel-data-error-view.missing-value.string', 'Data is missing a string field');
  }

  if (needsNumberField && !dataSummary.hasFieldType(FieldType.number)) {
    return t('panel.panel-data-error-view.missing-value.number', 'Data is missing a number field');
  }

  if (needsTimeField && !dataSummary.hasFieldType(FieldType.time)) {
    return t('panel.panel-data-error-view.missing-value.time', 'Data is missing a time field');
  }

  return t('panel.panel-data-error-view.missing-value.unknown', 'Cannot visualize data');
}

const getStyles = (theme: GrafanaTheme2) => {
  return {
    wrapper: css({
      display: 'flex',
      flexDirection: 'column',
      justifyContent: 'center',
      alignItems: 'center',
      height: '100%',
      width: '100%',
    }),
    message: css({
      textAlign: 'center',
      color: theme.colors.text.secondary,
      fontSize: theme.typography.size.lg,
      width: '100%',
    }),
    actions: css({
      marginTop: theme.spacing(2),
      display: 'flex',
      height: '50%',
      maxHeight: '150px',
      columnGap: theme.spacing(1),
      rowGap: theme.spacing(1),
      width: '100%',
      maxWidth: '600px',
    }),
    emptyStateIcon: css({
      color: theme.colors.text.secondary,
      marginBottom: theme.spacing(2),
    }),
  };
};
