import React, { FC, useCallback, useEffect, useState } from 'react';

import { Legend, LoadingPlaceholder } from '@grafana/ui';
import { useLocation } from 'react-router-dom';

// import logo from '../../img/logo.svg';
import PluginState from '../../plugin_state';

import ConfigurationForm from './parts/ConfigurationForm';
import RemoveCurrentConfigurationButton from './parts/RemoveCurrentConfigurationButton';
import StatusMessageBlock from './parts/StatusMessageBlock';
import { DataExporterPluginConfigPageProps } from 'types';

const PLUGIN_CONFIGURED_QUERY_PARAM = 'pluginConfigured';
const PLUGIN_CONFIGURED_QUERY_PARAM_TRUTHY_VALUE = 'true';

const DEFAULT_API_URL = 'http://localhost:8080';

/**
 * When everything is successfully configured, reload the page, and pass along a few query parameters
 * so that we avoid an infinite configuration-check/data-sync loop
 *
 * Don't refresh the page if the plugin is already enabled..
 */
export const reloadPageWithPluginConfiguredQueryParams = (pluginEnabled: boolean): void => {
  if (!pluginEnabled) {
    window.location.href = `${window.location.href}?${PLUGIN_CONFIGURED_QUERY_PARAM}=${PLUGIN_CONFIGURED_QUERY_PARAM_TRUTHY_VALUE}`;
  }
};

/**
 * remove the query params used to track state for a page reload after successful configuration, without triggering
 * a page reload
 * https://stackoverflow.com/a/19279428
 */
export const removePluginConfiguredQueryParams = (pluginIsEnabled?: boolean): void => {
  if (window.history.pushState && pluginIsEnabled) {
    const newurl = `${window.location.protocol}//${window.location.host}${window.location.pathname}`;
    window.history.pushState({ path: newurl }, '', newurl);
  }
};

export const PluginConfigPage: FC<DataExporterPluginConfigPageProps> = ({
  plugin: {
    meta: { jsonData, enabled: pluginIsEnabled },
  },
}) => {
  const { search } = useLocation();
  const queryParams = new URLSearchParams(search);
  const pluginConfiguredQueryParam = queryParams.get(PLUGIN_CONFIGURED_QUERY_PARAM);

  const pluginConfiguredRedirect = pluginConfiguredQueryParam === PLUGIN_CONFIGURED_QUERY_PARAM_TRUTHY_VALUE;

  const [checkingIfPluginIsConnected, setCheckingIfPluginIsConnected] = useState<boolean>(!pluginConfiguredRedirect);
  const [pluginConnectionCheckError, setPluginConnectionCheckError] = useState<string | null>(null);

  const [pluginIsConnected, setPluginIsConnected] = useState<Boolean | null>(pluginConfiguredRedirect);

  const [resettingPlugin, setResettingPlugin] = useState<boolean>(false);
  const [pluginResetError, setPluginResetError] = useState<string | null>(null);

  const pluginMetaDataExporterApiUrl = jsonData?.dataExporterApiUrl;
  const dataExporterApiUrl = pluginMetaDataExporterApiUrl || DEFAULT_API_URL;

  const resetQueryParams = useCallback(() => removePluginConfiguredQueryParams(pluginIsEnabled), [pluginIsEnabled]);

  useEffect(resetQueryParams, [resetQueryParams]);

  useEffect(() => {
    const configurePluginAndSyncData = async () => {
      /**
       * If the plugin has never been configured, DataExporterApiUrl will be undefined in the plugin's jsonData
       * In that case, check to see if DataExporter_API_URL has been supplied as an env var.
       * Supplying the env var basically allows to skip the configuration form
       * (check webpack.config.js to see how this is set)
       */
      if (!pluginMetaDataExporterApiUrl) {
        /**
         * DataExporterApiUrl is not yet saved in the grafana plugin settings, but has been supplied as an env var
         * lets auto-trigger a self-hosted plugin install w/ the DataExporterApiUrl passed in as an env var
         */
        const errorMsg = await PluginState.installPlugin(dataExporterApiUrl);
        if (errorMsg) {
          setPluginConnectionCheckError(errorMsg);
          setCheckingIfPluginIsConnected(false);
          return;
        }
      }

      /**
       * If the DataExporterApiUrl is not set in the plugin settings, and not supplied via an env var
       * there's no reason to check if the plugin is connected, we know it can't be
       */
      if (dataExporterApiUrl) {
        const pluginConnectionResponse = await PluginState.checkIfPluginIsConnected(dataExporterApiUrl);

        if (typeof pluginConnectionResponse === 'string') {
          setPluginConnectionCheckError(pluginConnectionResponse);
        }
      }
      setCheckingIfPluginIsConnected(false);
    };

    /**
     * don't check the plugin status (or trigger a data sync) if the user was just redirected after a successful
     * plugin setup
     */
    if (!pluginConfiguredRedirect) {
      configurePluginAndSyncData();
    }
  }, [pluginMetaDataExporterApiUrl, dataExporterApiUrl, pluginConfiguredRedirect]);

  const resetState = useCallback(() => {
    setPluginResetError(null);
    setPluginConnectionCheckError(null);
    setPluginIsConnected(null);
    resetQueryParams();
  }, [resetQueryParams]);

  /**
   * NOTE: there is a possible edge case when resetting the plugin, that would lead to an error message being shown
   * (which could be fixed by just reloading the page)
   * This would happen if the user removes the plugin configuration, leaves the page, then comes back to the plugin
   * configuration.
   *
   * This is because the props being passed into this component wouldn't reflect the actual plugin
   * provisioning state. The props would still have DataExporterApiUrl set in the plugin jsonData, so when we make the API
   * call to check the plugin state w/ DataExporter API the plugin-proxy would return a 502 Bad Gateway because the actual
   * provisioned plugin doesn't know about the DataExporterApiUrl.
   *
   * This could be fixed by instead of passing in the plugin provisioning information as props always fetching it
   * when this component renders (via a useEffect). We probably don't need to worry about this because it should happen
   * very rarely, if ever
   */
  const triggerPluginReset = useCallback(async () => {
    setResettingPlugin(true);
    resetState();

    try {
      await PluginState.resetPlugin();
    } catch (e) {
      // this should rarely, if ever happen, but we should handle the case nevertheless
      setPluginResetError('There was an error resetting your plugin, try again.');
    }

    setResettingPlugin(false);
  }, [resetState]);

  const onSuccessfulSetup = useCallback(async () => {
    reloadPageWithPluginConfiguredQueryParams(false);
  }, []);

  const RemoveConfigButton = useCallback(
    () => <RemoveCurrentConfigurationButton disabled={resettingPlugin} onClick={triggerPluginReset} />,
    [resettingPlugin, triggerPluginReset]
  );

  let content: React.ReactNode;

  if (checkingIfPluginIsConnected) {
    content = <LoadingPlaceholder text="Validating your plugin connection..." />;
  } else if (pluginConnectionCheckError || pluginResetError) {
    content = (
      <>
        <StatusMessageBlock text={(pluginConnectionCheckError || pluginResetError) as string} />
        <RemoveConfigButton />
      </>
    );
  } else if (!pluginIsConnected) {
    content = (
      <ConfigurationForm
        onSuccessfulSetup={onSuccessfulSetup}
        defaultDataExporterApiUrl={DEFAULT_API_URL}
      />
    );
  } else {
    // plugin is fully connected and synced
    content = <RemoveConfigButton />;
  }

  return (
    <>
      <Legend>Configure DataExporter</Legend>
      {pluginIsConnected ? (
        <>
          <p>
            Plugin is connected! Continue to DataExporter by clicking the{' '}
            {/* <img alt="DataExporter Logo" src={logo} width={18} /> icon over there 👈 */}
          </p>
          <StatusMessageBlock text={`Connected to DataExporter`} />
        </>
      ) : (
        <p>This page will help you configure the DataExporter plugin 👋</p>
      )}
      {content}
    </>
  );
};
