import { createContext, type Dispatch, type ReactNode, type SetStateAction, useContext } from 'react';

import { type CoreApp } from '@grafana/data';
import { type DataQuery } from '@grafana/schema';
import { type SavedQuery } from 'app/features/explore/QueryLibrary/types';

import { type OnSelectQueryType, type QueryLibraryEventsPropertyMap, QueryLibraryTab } from './types';

export type QueryLibraryDrawerOptions = {
  datasourceFilters?: string[];
  onSelectQuery?: OnSelectQueryType;
  options?: { isReplacingQuery?: boolean; onSave?: () => void; context?: string; highlightQuery?: string };
  query?: DataQuery;
};

/**
 * Context with state and action to interact with Query Library. The Query Library feature consists of a drawer
 * that shows existing queries and allows users to use them and manage them and then an AddQueryModal which allows
 * users to save a query into the library. Both of those are included in Grafana AppChrome component.
 *
 * Use this context to interact with those components, showing, hiding and setting initial state for them.
 */
export type QueryLibraryContextType = {
  /**
   * Opens a drawer with query library.
   * @param datasourceFilters Data source names that will be used for initial filter in the library.
   * @param onSelectQuery Callback to be called when a query is selected from the library.
   * @param options.context Used for QueryEditor. Should identify the context this is called from, like 'explore' or
   *   'dashboard'.
   * @param newQuery New query to be added to the library.
   */
  openDrawer: (options: QueryLibraryDrawerOptions) => void;
  closeDrawer: (isSelectingQuery?: boolean) => void;
  isDrawerOpen: boolean;
  onSave?: () => void;

  /**
   * Returns both save and replace action buttons that can be used to save or replace a query to the library.
   * @param query
   */
  renderSavedQueryButtons: (
    query: DataQuery,
    app?: CoreApp,
    onUpdateSuccess?: () => void,
    onSelectQuery?: (query: DataQuery) => void,
    datasourceFilters?: string[],
    parentRef?: React.RefObject<HTMLDivElement | null>,
    showAsButtonHeader?: boolean
  ) => ReactNode;

  /**
   * Returns a header component for editing queries from the library.
   * used in places like Explore
   * @param query
   * @param app
   * @param queryLibraryRef
   * @param onCancelEdit
   * @param onUpdateSuccess
   */
  renderQueryLibraryEditingHeader: (
    query: DataQuery,
    app?: CoreApp,
    queryLibraryRef?: string,
    onCancelEdit?: () => void,
    onUpdateSuccess?: () => void,
    onSelectQuery?: (query: DataQuery) => void
  ) => ReactNode;

  queryLibraryEnabled: boolean;
  context: string;
  triggerAnalyticsEvent: (
    handleAnalyticEvent: (properties?: QueryLibraryEventsPropertyMap) => void,
    properties?: QueryLibraryEventsPropertyMap,
    contextOverride?: string
  ) => void;
  setNewQuery: (query?: SavedQuery) => void;
  onSelectQuery: OnSelectQueryType;
  onFavorite: (uid: string) => void;
  onUnfavorite: (uid: string) => void;
  userFavorites: { [key: string]: boolean };
  setUserFavorites: Dispatch<SetStateAction<{ [key: string]: boolean }>>;
  isEditingQuery: boolean;
  setIsEditingQuery: (isEditingQuery: boolean) => void;
  onAddHistoryQueryToLibrary: (newQuery: SavedQuery) => void;
  activeTab: QueryLibraryTab;
  setActiveTab: (activeTab: QueryLibraryTab) => void;
  onTabChange: (activeTab: QueryLibraryTab) => void;
  highlightedQuery: string | undefined;
  newQuery: SavedQuery | undefined;
  activeDatasources: string[];
  /** Set a guard function that returns true to allow closing, false to prevent closing */
  setCloseGuard: (shouldAllowClose: () => boolean) => void;
  /** Template variable overrides keyed by unresolved variable string (for example `${var}`) */
  templateVariableOverrides: Record<string, string>;
  setTemplateVariableOverrides: (overrides: Record<string, string>) => void;
};

export const QueryLibraryContext = createContext<QueryLibraryContextType>({
  openDrawer: () => {},
  closeDrawer: () => {},
  isDrawerOpen: false,

  setNewQuery: () => {},
  onSave: () => {},

  renderSavedQueryButtons: () => {
    return null;
  },

  renderQueryLibraryEditingHeader: () => {
    return null;
  },

  queryLibraryEnabled: false,
  context: 'unknown',
  triggerAnalyticsEvent: () => {},
  onSelectQuery: () => {},
  onFavorite: () => {},
  onUnfavorite: () => {},
  userFavorites: {},
  setUserFavorites: (_favorites) => {},
  isEditingQuery: false,
  setIsEditingQuery: () => {},
  onAddHistoryQueryToLibrary: () => {},
  activeTab: QueryLibraryTab.ALL,
  setActiveTab: () => {},
  onTabChange: () => {},
  highlightedQuery: undefined,
  newQuery: undefined,
  activeDatasources: [],
  setCloseGuard: () => {},
  templateVariableOverrides: {},
  setTemplateVariableOverrides: () => {},
});

export function useQueryLibraryContext() {
  return useContext(QueryLibraryContext);
}
