import React, { useCallback, useMemo } from 'react';

import config from 'app/core/config';
import { VizTypePickerPlugin } from './VizTypePickerPlugin';
import { EmptySearchResult, stylesFactory, useTheme } from '@grafana/ui';
import { GrafanaTheme, PanelPluginMeta, PluginState } from '@grafana/data';
import { css } from '@emotion/css';

export interface Props {
  current: PanelPluginMeta;
  onTypeChange: (newType: PanelPluginMeta, withModKey?: boolean) => void;
  searchQuery: string;
  onClose: () => void;
}

export function getAllPanelPluginMeta(): PanelPluginMeta[] {
  const allPanels = config.panels;

  return Object.keys(allPanels)
    .filter((key) => allPanels[key]['hideFromList'] === false)
    .map((key) => allPanels[key])
    .sort((a: PanelPluginMeta, b: PanelPluginMeta) => a.sort - b.sort);
}

export function filterPluginList(
  pluginsList: PanelPluginMeta[],
  searchQuery: string,
  current: PanelPluginMeta
): PanelPluginMeta[] {
  if (!searchQuery.length) {
    return pluginsList.filter((p) => {
      if (p.state === PluginState.deprecated) {
        return current.id === p.id;
      }
      return true;
    });
  }

  const query = searchQuery.toLowerCase();
  const first: PanelPluginMeta[] = [];
  const match: PanelPluginMeta[] = [];

  for (const item of pluginsList) {
    if (item.state === PluginState.deprecated && current.id !== item.id) {
      continue;
    }

    const name = item.name.toLowerCase();
    const idx = name.indexOf(query);

    if (idx === 0) {
      first.push(item);
    } else if (idx > 0) {
      match.push(item);
    }
  }

  return first.concat(match);
}

export const VizTypePicker: React.FC<Props> = ({ searchQuery, onTypeChange, current }) => {
  const theme = useTheme();
  const styles = getStyles(theme);
  const pluginsList: PanelPluginMeta[] = useMemo(() => {
    return getAllPanelPluginMeta();
  }, []);

  const getFilteredPluginList = useCallback((): PanelPluginMeta[] => {
    return filterPluginList(pluginsList, searchQuery, current);
  }, [current, pluginsList, searchQuery]);

  const renderVizPlugin = (plugin: PanelPluginMeta, index: number) => {
    const isCurrent = plugin.id === current.id;
    const filteredPluginList = getFilteredPluginList();

    const matchesQuery = filteredPluginList.indexOf(plugin) > -1;
    return (
      <VizTypePickerPlugin
        disabled={!matchesQuery && !!searchQuery}
        key={plugin.id}
        isCurrent={isCurrent}
        plugin={plugin}
        onClick={(e) => onTypeChange(plugin, e.metaKey || e.ctrlKey || e.altKey)}
      />
    );
  };

  const filteredPluginList = getFilteredPluginList();
  const hasResults = filteredPluginList.length > 0;
  const renderList = filteredPluginList.concat(pluginsList.filter((p) => filteredPluginList.indexOf(p) === -1));

  return (
    <div className={styles.grid}>
      {hasResults ? (
        renderList.map((plugin, index) => {
          if (plugin.state === PluginState.deprecated) {
            return null;
          }
          return renderVizPlugin(plugin, index);
        })
      ) : (
        <EmptySearchResult>Could not find anything matching your query</EmptySearchResult>
      )}
    </div>
  );
};

VizTypePicker.displayName = 'VizTypePicker';

const getStyles = stylesFactory((theme: GrafanaTheme) => {
  return {
    grid: css`
      max-width: 100%;
      display: grid;
      grid-gap: ${theme.spacing.sm};
    `,
  };
});
