import { useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom-v5-compat';

import { AppEvents } from '@grafana/data';
import { config, locationService, reportInteraction } from '@grafana/runtime';
import { Button, ConfirmModal, Stack } from '@grafana/ui';
import appEvents from 'app/core/app_events';
import { useQueryParams } from 'app/core/hooks/useQueryParams';
import { removePluginFromNavTree } from 'app/core/reducers/navBarTree';
import { useDispatch } from 'app/types';

import {
  useInstallStatus,
  useUninstallStatus,
  useInstall,
  useUninstall,
  useUnsetInstall,
  useFetchDetailsLazy,
} from '../../state/hooks';
import { trackPluginInstalled, trackPluginUninstalled } from '../../tracking';
import { CatalogPlugin, PluginStatus, PluginTabIds, Version } from '../../types';

const PLUGIN_UPDATE_INTERACTION_EVENT_NAME = 'plugin_update_clicked';

type InstallControlsButtonProps = {
  plugin: CatalogPlugin;
  pluginStatus: PluginStatus;
  latestCompatibleVersion?: Version;
  hasInstallWarning?: boolean;
  setNeedReload?: (needReload: boolean) => void;
};

export function InstallControlsButton({
  plugin,
  pluginStatus,
  latestCompatibleVersion,
  hasInstallWarning,
  setNeedReload,
}: InstallControlsButtonProps) {
  const dispatch = useDispatch();
  const [queryParams] = useQueryParams();
  const location = useLocation();
  const { isInstalling, error: errorInstalling } = useInstallStatus();
  const { isUninstalling, error: errorUninstalling } = useUninstallStatus();
  const install = useInstall();
  const uninstall = useUninstall();
  const unsetInstall = useUnsetInstall();
  const fetchDetails = useFetchDetailsLazy();
  const [isConfirmModalVisible, setIsConfirmModalVisible] = useState(false);
  const showConfirmModal = () => setIsConfirmModalVisible(true);
  const hideConfirmModal = () => setIsConfirmModalVisible(false);
  const uninstallBtnText = isUninstalling ? 'Uninstalling' : 'Uninstall';
  const trackingProps = {
    plugin_id: plugin.id,
    plugin_type: plugin.type,
    path: location.pathname,
    creator_team: 'grafana_plugins_catalog',
    schema_version: '1.0.0',
  };

  useEffect(() => {
    return () => {
      // Remove possible installation errors
      unsetInstall();
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const onInstall = async () => {
    trackPluginInstalled(trackingProps);
    const result = await install(plugin.id, latestCompatibleVersion?.version);
    if (!errorInstalling && !('error' in result)) {
      let successMessage = `Installed ${plugin.name}`;
      if (config.pluginAdminExternalManageEnabled) {
        successMessage = 'Install requested, this may take a few minutes.';
      }

      appEvents.emit(AppEvents.alertSuccess, [successMessage]);
      if (plugin.type === 'app') {
        setNeedReload?.(true);
      }

      await fetchDetails(plugin.id);
    }
  };

  const onUninstall = async () => {
    hideConfirmModal();
    trackPluginUninstalled(trackingProps);
    await uninstall(plugin.id);
    if (!errorUninstalling) {
      // If an app plugin is uninstalled we need to reset the active tab when the config / dashboards tabs are removed.
      const activePageId = queryParams.page;
      const isViewingAppConfigPage = activePageId !== PluginTabIds.OVERVIEW && activePageId !== PluginTabIds.VERSIONS;
      if (isViewingAppConfigPage) {
        locationService.replace(`${location.pathname}?page=${PluginTabIds.OVERVIEW}`);
      }

      let successMessage = `Uninstalled ${plugin.name}`;
      if (config.pluginAdminExternalManageEnabled) {
        successMessage = 'Uninstall requested, this may take a few minutes.';
      }

      appEvents.emit(AppEvents.alertSuccess, [successMessage]);
      if (plugin.type === 'app') {
        dispatch(removePluginFromNavTree({ pluginID: plugin.id }));
        setNeedReload?.(false);
      }
    }
  };

  const onUpdate = async () => {
    reportInteraction(PLUGIN_UPDATE_INTERACTION_EVENT_NAME, trackingProps);

    await install(plugin.id, latestCompatibleVersion?.version, PluginStatus.UPDATE);
    if (!errorInstalling) {
      appEvents.emit(AppEvents.alertSuccess, [`Updated ${plugin.name}`]);
    }
  };

  let disableUninstall = shouldDisableUninstall(isUninstalling, plugin);

  let uninstallTitle = '';
  if (plugin.isPreinstalled.found) {
    disableUninstall = true;
    uninstallTitle = 'Preinstalled plugin. Remove from Grafana config before uninstalling.';
  }

  const uninstallControls = (
    <>
      <ConfirmModal
        isOpen={isConfirmModalVisible}
        title={`Uninstall ${plugin.name}`}
        body="Are you sure you want to uninstall this plugin?"
        confirmText="Confirm"
        icon="exclamation-triangle"
        onConfirm={onUninstall}
        onDismiss={hideConfirmModal}
      />
      <Button variant="destructive" disabled={disableUninstall} onClick={showConfirmModal} title={uninstallTitle}>
        {uninstallBtnText}
      </Button>
    </>
  );

  if (pluginStatus === PluginStatus.UNINSTALL) {
    return (
      <Stack alignItems="flex-start" width="auto" height="auto">
        {uninstallControls}
      </Stack>
    );
  }

  if (!plugin.isPublished || hasInstallWarning) {
    // Cannot be updated or installed
    return null;
  }

  if (pluginStatus === PluginStatus.UPDATE) {
    const disableUpdate = config.pluginAdminExternalManageEnabled ? plugin.isUpdatingFromInstance : isInstalling;

    return (
      <Stack alignItems="flex-start" width="auto" height="auto">
        {!plugin.isManaged && !plugin.isPreinstalled.withVersion && (
          <Button disabled={disableUpdate} onClick={onUpdate}>
            {isInstalling ? 'Updating' : 'Update'}
          </Button>
        )}
        {uninstallControls}
      </Stack>
    );
  }
  const shouldDisable = isInstalling || errorInstalling || (!config.angularSupportEnabled && plugin.angularDetected);
  return (
    <Button disabled={shouldDisable} onClick={onInstall}>
      {isInstalling ? 'Installing' : 'Install'}
    </Button>
  );
}

function shouldDisableUninstall(isUninstalling: boolean, plugin: CatalogPlugin) {
  if (config.pluginAdminExternalManageEnabled) {
    return plugin.isUninstallingFromInstance || !plugin.isFullyInstalled || plugin.isUpdatingFromInstance;
  }

  return isUninstalling;
}
