import { startCase } from 'lodash';
import PropTypes from 'prop-types';
import React, { PureComponent } from 'react';
import {
  addUrlProtocolPrefix,
  getEnvironmentType,
} from '../../../../app/scripts/lib/util';
import { ENVIRONMENT_TYPE_POPUP } from '../../../../shared/constants/app';
import {
  MetaMetricsEventCategory,
  MetaMetricsEventKeyType,
  MetaMetricsEventName,
} from '../../../../shared/constants/metametrics';
import { IPFS_DEFAULT_GATEWAY_URL } from '../../../../shared/constants/network';
import {
  AUTO_DETECT_TOKEN_LEARN_MORE_LINK,
  COINGECKO_LINK,
  CONSENSYS_PRIVACY_LINK,
  CRYPTOCOMPARE_LINK,
  ETHERSCAN_PRIVACY_LINK,
  PRIVACY_POLICY_LINK,
} from '../../../../shared/lib/ui-utils';
import SRPQuiz from '../../../components/app/srp-quiz-modal/SRPQuiz';
import {
  BUTTON_SIZES,
  Button,
  Box,
  Text,
} from '../../../components/component-library';
import TextField from '../../../components/ui/text-field';
import ToggleButton from '../../../components/ui/toggle-button';
import {
  Display,
  FlexDirection,
  JustifyContent,
  TextColor,
  TextVariant,
} from '../../../helpers/constants/design-system';
import { ADD_POPULAR_CUSTOM_NETWORK } from '../../../helpers/constants/routes';
import {
  getNumberOfSettingsInSection,
  handleSettingsRefs,
} from '../../../helpers/utils/settings-search';

export default class SecurityTab extends PureComponent {
  static contextTypes = {
    t: PropTypes.func,
    trackEvent: PropTypes.func,
  };

  static propTypes = {
    warning: PropTypes.string,
    history: PropTypes.object,
    openSeaEnabled: PropTypes.bool,
    setOpenSeaEnabled: PropTypes.func,
    useNftDetection: PropTypes.bool,
    setUseNftDetection: PropTypes.func,
    participateInMetaMetrics: PropTypes.bool.isRequired,
    setParticipateInMetaMetrics: PropTypes.func.isRequired,
    showIncomingTransactions: PropTypes.bool.isRequired,
    setShowIncomingTransactionsFeatureFlag: PropTypes.func.isRequired,
    setUsePhishDetect: PropTypes.func.isRequired,
    usePhishDetect: PropTypes.bool.isRequired,
    setUse4ByteResolution: PropTypes.func.isRequired,
    use4ByteResolution: PropTypes.bool.isRequired,
    useTokenDetection: PropTypes.bool.isRequired,
    setUseTokenDetection: PropTypes.func.isRequired,
    setIpfsGateway: PropTypes.func.isRequired,
    ipfsGateway: PropTypes.string.isRequired,
    useMultiAccountBalanceChecker: PropTypes.bool.isRequired,
    setUseMultiAccountBalanceChecker: PropTypes.func.isRequired,
    useCurrencyRateCheck: PropTypes.bool.isRequired,
    setUseCurrencyRateCheck: PropTypes.func.isRequired,
    useAddressBarEnsResolution: PropTypes.bool.isRequired,
    setUseAddressBarEnsResolution: PropTypes.func.isRequired,
  };

  state = {
    ipfsGateway: this.props.ipfsGateway,
    ipfsGatewayError: '',
    srpQuizModalVisible: false,
    ipfsToggle: false,
  };

  settingsRefCounter = 0;

  settingsRefs = Array(
    getNumberOfSettingsInSection(
      this.context.t,
      this.context.t('securityAndPrivacy'),
    ),
  )
    .fill(undefined)
    .map(() => {
      return React.createRef();
    });

  componentDidUpdate() {
    const { t } = this.context;
    handleSettingsRefs(t, t('securityAndPrivacy'), this.settingsRefs);
  }

  componentDidMount() {
    const { t } = this.context;
    handleSettingsRefs(t, t('securityAndPrivacy'), this.settingsRefs);
  }

  toggleSetting(value, eventName, eventAction, toggleMethod) {
    this.context.trackEvent({
      category: MetaMetricsEventCategory.Settings,
      event: eventName,
      properties: {
        action: eventAction,
        legacy_event: true,
      },
    });
    toggleMethod(!value);
  }

  hideSrpQuizModal = () => this.setState({ srpQuizModalVisible: false });

  renderSeedWords() {
    const { t } = this.context;

    return (
      <>
        <div
          ref={this.settingsRefs[0]}
          className="settings-page__security-tab-sub-header"
        >
          {t('secretRecoveryPhrase')}
        </div>
        <div className="settings-page__content-padded">
          <Button
            data-testid="reveal-seed-words"
            type="danger"
            size={BUTTON_SIZES.LG}
            onClick={(event) => {
              event.preventDefault();
              this.context.trackEvent({
                category: MetaMetricsEventCategory.Settings,
                event: MetaMetricsEventName.KeyExportSelected,
                properties: {
                  key_type: MetaMetricsEventKeyType.Srp,
                  location: 'Settings',
                },
              });
              this.context.trackEvent({
                category: MetaMetricsEventCategory.Settings,
                event: MetaMetricsEventName.SrpRevealClicked,
                properties: {
                  key_type: MetaMetricsEventKeyType.Srp,
                  location: 'Settings',
                },
              });
              this.setState({ srpQuizModalVisible: true });
            }}
          >
            {t('revealSeedWords')}
          </Button>
          {this.state.srpQuizModalVisible && (
            <SRPQuiz
              isOpen={this.state.srpQuizModalVisible}
              onClose={this.hideSrpQuizModal}
            />
          )}
        </div>
      </>
    );
  }

  renderIncomingTransactionsOptIn() {
    const { t } = this.context;
    const { showIncomingTransactions, setShowIncomingTransactionsFeatureFlag } =
      this.props;

    return (
      <Box
        ref={this.settingsRefs[1]}
        className="settings-page__content-row"
        display={Display.Flex}
        flexDirection={FlexDirection.Row}
        justifyContent={JustifyContent.spaceBetween}
      >
        <div className="settings-page__content-item">
          <span>{t('showIncomingTransactions')}</span>
          <div className="settings-page__content-description">
            {t('showIncomingTransactionsDescription', [
              // TODO: Update to use real link
              <a
                href={ETHERSCAN_PRIVACY_LINK}
                target="_blank"
                rel="noopener noreferrer"
                key="etherscan-privacy-link"
              >
                {t('etherscan')}
              </a>,
              // TODO: Update to use real link
              <a
                href={CONSENSYS_PRIVACY_LINK}
                target="_blank"
                rel="noopener noreferrer"
                key="ic-consensys-privacy-link"
              >
                {t('privacyMsg')}
              </a>,
            ])}
          </div>
        </div>
        <div
          className="settings-page__content-item-col"
          data-testid="showIncomingTransactions"
        >
          <ToggleButton
            value={showIncomingTransactions}
            onToggle={(value) => setShowIncomingTransactionsFeatureFlag(!value)}
            offLabel={t('off')}
            onLabel={t('on')}
          />
        </div>
      </Box>
    );
  }

  renderPhishingDetectionToggle() {
    const { t } = this.context;
    const { usePhishDetect, setUsePhishDetect } = this.props;

    return (
      <Box
        ref={this.settingsRefs[2]}
        className="settings-page__content-row"
        display={Display.Flex}
        flexDirection={FlexDirection.Row}
        justifyContent={JustifyContent.spaceBetween}
      >
        <div className="settings-page__content-item">
          <span>{t('usePhishingDetection')}</span>
          <div className="settings-page__content-description">
            {t('usePhishingDetectionDescription')}
          </div>
        </div>

        <div
          className="settings-page__content-item-col"
          data-testid="usePhishingDetection"
        >
          <ToggleButton
            value={usePhishDetect}
            onToggle={(value) => setUsePhishDetect(!value)}
            offLabel={t('off')}
            onLabel={t('on')}
          />
        </div>
      </Box>
    );
  }

  renderUse4ByteResolutionToggle() {
    const { t } = this.context;
    const { use4ByteResolution, setUse4ByteResolution } = this.props;
    return (
      <div ref={this.settingsRefs[3]} className="settings-page__content-row">
        <div className="settings-page__content-item">
          <span>{t('use4ByteResolution')}</span>
          <div className="settings-page__content-description">
            {t('use4ByteResolutionDescription')}
          </div>
        </div>
        <div className="settings-page__content-item">
          <div
            className="settings-page__content-item-col"
            data-testid="4byte-resolution-container"
          >
            <ToggleButton
              value={use4ByteResolution}
              onToggle={(value) => setUse4ByteResolution(!value)}
              offLabel={t('off')}
              onLabel={t('on')}
            />
          </div>
        </div>
      </div>
    );
  }

  renderMetaMetricsOptIn() {
    const { t } = this.context;
    const { participateInMetaMetrics, setParticipateInMetaMetrics } =
      this.props;

    return (
      <Box
        ref={this.settingsRefs[4]}
        className="settings-page__content-row"
        display={Display.Flex}
        flexDirection={FlexDirection.Row}
        justifyContent={JustifyContent.spaceBetween}
      >
        <div className="settings-page__content-item">
          <span>{t('participateInMetaMetrics')}</span>
          <div className="settings-page__content-description">
            <span>{t('participateInMetaMetricsDescription')}</span>
          </div>
        </div>

        <div
          className="settings-page__content-item-col"
          data-testid="participateInMetaMetrics"
        >
          <ToggleButton
            value={participateInMetaMetrics}
            onToggle={(value) => setParticipateInMetaMetrics(!value)}
            offLabel={t('off')}
            onLabel={t('on')}
          />
        </div>
      </Box>
    );
  }

  renderChooseYourNetworkButton() {
    const { t } = this.context;

    return (
      <Box
        ref={this.settingsRefs[5]}
        className="settings-page__content-row"
        data-testid="advanced-setting-choose-your-network"
        display={Display.Flex}
        flexDirection={FlexDirection.Column}
      >
        <div className="settings-page__content-item">
          <span>{t('chooseYourNetwork')}</span>
          <div className="settings-page__content-description">
            {t('chooseYourNetworkDescription', [
              // TODO: Update to use real link
              <a
                href={CONSENSYS_PRIVACY_LINK}
                target="_blank"
                rel="noopener noreferrer"
                key="cyn-consensys-privacy-link"
              >
                {t('privacyMsg')}
              </a>,
            ])}
          </div>
        </div>
        <div className="settings-page__content-item-col">
          <Button
            type="secondary"
            className="settings-page__button"
            onClick={() => {
              getEnvironmentType() === ENVIRONMENT_TYPE_POPUP
                ? global.platform.openExtensionInBrowser(
                    ADD_POPULAR_CUSTOM_NETWORK,
                  )
                : this.props.history.push(ADD_POPULAR_CUSTOM_NETWORK);
            }}
          >
            {t('addCustomNetwork')}
          </Button>
        </div>
      </Box>
    );
  }

  renderIpfsGatewayControl() {
    const { t } = this.context;
    const { ipfsGatewayError } = this.state;
    const { useAddressBarEnsResolution, setUseAddressBarEnsResolution } =
      this.props;

    const handleIpfsGatewaySave = (gateway) => {
      const url = gateway ? new URL(addUrlProtocolPrefix(gateway)) : '';
      const { host } = url;

      this.props.setIpfsGateway(host);
    };

    const handleIpfsGatewayChange = (url) => {
      this.setState(() => {
        let ipfsError = '';

        try {
          const urlObj = new URL(addUrlProtocolPrefix(url));
          if (!urlObj.host) {
            throw new Error();
          }

          // don't allow the use of this gateway
          if (urlObj.host === 'gateway.ipfs.io') {
            throw new Error('Forbidden gateway');
          }
        } catch (error) {
          ipfsError =
            error.message === 'Forbidden gateway'
              ? t('forbiddenIpfsGateway')
              : t('invalidIpfsGateway');
        }

        handleIpfsGatewaySave(url);
        return {
          ipfsGateway: url,
          ipfsGatewayError: ipfsError,
        };
      });
    };

    const handleIpfsToggle = (url) => {
      url?.length < 1
        ? handleIpfsGatewayChange(IPFS_DEFAULT_GATEWAY_URL)
        : handleIpfsGatewayChange('');
    };
    return (
      <Box
        ref={this.settingsRefs[6]}
        className="settings-page__content-row"
        data-testid="setting-ipfs-gateway"
        display={Display.Flex}
        flexDirection={FlexDirection.Column}
      >
        <div className="settings-page__content-item">
          <span>{t('ipfsGateway')}</span>
          <div className="settings-page__content-description">
            {t('ipfsGatewayDescription')}
          </div>
        </div>
        <div className="settings-page__content-item-col">
          <ToggleButton
            value={this.state.ipfsGateway}
            onToggle={(value) => {
              handleIpfsToggle(value);
              this.setState({ ipfsToggle: Boolean(value) });
            }}
            offLabel={t('off')}
            onLabel={t('on')}
          />
        </div>
        {!this.state.ipfsToggle && (
          <div className="settings-page__content-item">
            <span>{t('addIPFSGateway')}</span>
            <div className="settings-page__content-item-col">
              <TextField
                type="text"
                disabled={!this.state.ipfsGateway}
                value={this.state.ipfsGateway}
                onChange={(e) => handleIpfsGatewayChange(e.target.value)}
                error={ipfsGatewayError}
                fullWidth
                margin="dense"
              />
            </div>
          </div>
        )}
        <Box
          className="settings-page__content-row"
          display={Display.Flex}
          flexDirection={FlexDirection.Row}
          justifyContent={JustifyContent.spaceBetween}
          ref={this.settingsRefs[10]}
          marginTop={3}
          id="ens-domains"
        >
          <div>
            {t('ensDomainsSettingTitle')}
            <div className="settings-page__content-description">
              <Text color={TextColor.inherit} variant={TextVariant.inherit}>
                {t('ensDomainsSettingDescriptionIntro')}
              </Text>
              <Box
                as="ul"
                marginTop={4}
                marginBottom={4}
                paddingInlineStart={4}
                style={{ listStyleType: 'circle' }}
              >
                <Text
                  as="li"
                  color={TextColor.inherit}
                  variant={TextVariant.inherit}
                >
                  {t('ensDomainsSettingDescriptionPoint1')}
                </Text>
                <Text
                  as="li"
                  color={TextColor.inherit}
                  variant={TextVariant.inherit}
                >
                  {t('ensDomainsSettingDescriptionPoint2')}
                </Text>
                <Text
                  as="li"
                  color={TextColor.inherit}
                  variant={TextVariant.inherit}
                >
                  {t('ensDomainsSettingDescriptionPoint3')}
                </Text>
              </Box>
              <Text color={TextColor.inherit} variant={TextVariant.inherit}>
                {t('ensDomainsSettingDescriptionOutro')}
              </Text>
            </div>
          </div>

          <div
            className="settings-page__content-item-col"
            data-testid="ipfs-gateway-resolution-container"
          >
            <ToggleButton
              value={useAddressBarEnsResolution}
              onToggle={(value) => setUseAddressBarEnsResolution(!value)}
              offLabel={t('off')}
              onLabel={t('on')}
            />
          </div>
        </Box>
      </Box>
    );
  }

  renderAutoDetectTokensToggle() {
    const { t } = this.context;
    const { useTokenDetection, setUseTokenDetection } = this.props;

    return (
      <Box
        ref={this.settingsRefs[7]}
        className="settings-page__content-row"
        data-testid="advanced-setting-gas-fee-estimation"
        display={Display.Flex}
        flexDirection={FlexDirection.Row}
        justifyContent={JustifyContent.spaceBetween}
        id="advanced-settings-autodetect-tokens"
      >
        <div className="settings-page__content-item">
          <span>{t('autoDetectTokens')}</span>
          <div className="settings-page__content-description">
            {t('autoDetectTokensDescription', [
              // TODO: Update to use real link
              <a
                href={AUTO_DETECT_TOKEN_LEARN_MORE_LINK}
                target="_blank"
                rel="noopener noreferrer"
                key="cyn-consensys-privacy-link"
              >
                {startCase(t('learnMore'))}
              </a>,
            ])}
          </div>
        </div>

        <div
          className="settings-page__content-item-col"
          data-testid="autoDetectTokens"
        >
          <ToggleButton
            value={useTokenDetection}
            onToggle={(value) => {
              this.toggleSetting(
                value,
                MetaMetricsEventName.KeyAutoDetectTokens,
                MetaMetricsEventName.KeyAutoDetectTokens,
                setUseTokenDetection,
              );
            }}
            offLabel={t('off')}
            onLabel={t('on')}
          />
        </div>
      </Box>
    );
  }

  renderBatchAccountBalanceRequestsToggle() {
    const { t } = this.context;
    const { useMultiAccountBalanceChecker, setUseMultiAccountBalanceChecker } =
      this.props;

    return (
      <Box
        ref={this.settingsRefs[8]}
        className="settings-page__content-row"
        display={Display.Flex}
        flexDirection={FlexDirection.Row}
        justifyContent={JustifyContent.spaceBetween}
      >
        <div className="settings-page__content-item">
          <span>{t('useMultiAccountBalanceChecker')}</span>
          <div className="settings-page__content-description">
            {t('useMultiAccountBalanceCheckerSettingDescription')}
          </div>
        </div>

        <div
          className="settings-page__content-item-col"
          data-testid="useMultiAccountBalanceChecker"
        >
          <ToggleButton
            value={useMultiAccountBalanceChecker}
            onToggle={(value) => {
              this.toggleSetting(
                value,
                MetaMetricsEventName.KeyBatchAccountBalanceRequests,
                MetaMetricsEventName.KeyBatchAccountBalanceRequests,
                setUseMultiAccountBalanceChecker,
              );
            }}
            offLabel={t('off')}
            onLabel={t('on')}
          />
        </div>
      </Box>
    );
  }

  renderCurrencyRateCheckToggle() {
    const { t } = this.context;
    const { useCurrencyRateCheck, setUseCurrencyRateCheck } = this.props;

    return (
      <Box
        ref={this.settingsRefs[9]}
        className="settings-page__content-row"
        display={Display.Flex}
        flexDirection={FlexDirection.Row}
        justifyContent={JustifyContent.spaceBetween}
      >
        <div className="settings-page__content-item">
          <span>{t('currencyRateCheckToggle')}</span>
          <div className="settings-page__content-description">
            {t('currencyRateCheckToggleDescription', [
              <a
                key="coingecko_link"
                href={COINGECKO_LINK}
                rel="noreferrer"
                target="_blank"
              >
                {t('coingecko')}
              </a>,
              <a
                key="cryptocompare_link"
                href={CRYPTOCOMPARE_LINK}
                rel="noreferrer"
                target="_blank"
              >
                {t('cryptoCompare')}
              </a>,
              <a
                key="privacy_policy_link"
                href={PRIVACY_POLICY_LINK}
                rel="noreferrer"
                target="_blank"
              >
                {t('privacyMsg')}
              </a>,
            ])}
          </div>
        </div>

        <div
          className="settings-page__content-item-col"
          data-testid="currencyRateCheckToggle"
        >
          <ToggleButton
            value={useCurrencyRateCheck}
            onToggle={(value) => setUseCurrencyRateCheck(!value)}
            offLabel={t('off')}
            onLabel={t('on')}
          />
        </div>
      </Box>
    );
  }

  renderOpenSeaEnabledToggle() {
    const { t } = this.context;
    const {
      openSeaEnabled,
      setOpenSeaEnabled,
      useNftDetection,
      setUseNftDetection,
    } = this.props;

    return (
      <Box
        ref={this.settingsRefs[11]}
        className="settings-page__content-row"
        display={Display.Flex}
        flexDirection={FlexDirection.Row}
        justifyContent={JustifyContent.spaceBetween}
      >
        <div className="settings-page__content-item">
          <span>{t('displayNftMedia')}</span>
          <div className="settings-page__content-description">
            {t('displayNftMediaDescription')}
          </div>
        </div>

        <div
          className="settings-page__content-item-col"
          data-testid="displayNftMedia"
        >
          <ToggleButton
            value={openSeaEnabled}
            onToggle={(value) => {
              this.context.trackEvent({
                category: MetaMetricsEventCategory.Settings,
                event: 'Enabled/Disable OpenSea',
                properties: {
                  action: 'Enabled/Disable OpenSea',
                  legacy_event: true,
                },
              });
              // value is positive when being toggled off
              if (value && useNftDetection) {
                setUseNftDetection(false);
              }
              setOpenSeaEnabled(!value);
            }}
            offLabel={t('off')}
            onLabel={t('on')}
          />
        </div>
      </Box>
    );
  }

  renderNftDetectionToggle() {
    const { t } = this.context;
    const {
      openSeaEnabled,
      setOpenSeaEnabled,
      useNftDetection,
      setUseNftDetection,
    } = this.props;
    return (
      <Box
        ref={this.settingsRefs[12]}
        className="settings-page__content-row"
        display={Display.Flex}
        flexDirection={FlexDirection.Row}
        justifyContent={JustifyContent.spaceBetween}
      >
        <div className="settings-page__content-item">
          <span>{t('useNftDetection')}</span>
          <div className="settings-page__content-description">
            <Text color={TextColor.textAlternative}>
              {t('useNftDetectionDescription')}
            </Text>
            <ul className="settings-page__content-unordered-list">
              <li>{t('useNftDetectionDescriptionLine2')}</li>
              <li>{t('useNftDetectionDescriptionLine3')}</li>
              <li>{t('useNftDetectionDescriptionLine4')}</li>
            </ul>
            <Text color={TextColor.textAlternative} paddingTop={4}>
              {t('useNftDetectionDescriptionLine5')}
            </Text>
          </div>
        </div>

        <div
          className="settings-page__content-item-col"
          data-testid="useNftDetection"
        >
          <ToggleButton
            value={useNftDetection}
            onToggle={(value) => {
              this.context.trackEvent({
                category: MetaMetricsEventCategory.Settings,
                event: 'NFT Detected',
                properties: {
                  action: 'NFT Detected',
                  legacy_event: true,
                },
              });
              if (!value && !openSeaEnabled) {
                setOpenSeaEnabled(!value);
              }
              setUseNftDetection(!value);
            }}
            offLabel={t('off')}
            onLabel={t('on')}
          />
        </div>
      </Box>
    );
  }

  render() {
    const { warning } = this.props;

    return (
      <div className="settings-page__body">
        {warning && <div className="settings-tab__error">{warning}</div>}
        <span className="settings-page__security-tab-sub-header__bold">
          {this.context.t('security')}
        </span>
        {this.renderSeedWords()}
        <span className="settings-page__security-tab-sub-header__bold">
          {this.context.t('privacy')}
        </span>
        <div>
          <span className="settings-page__security-tab-sub-header">
            {this.context.t('alerts')}
          </span>
        </div>
        <div className="settings-page__content-padded">
          {this.renderPhishingDetectionToggle()}
        </div>
        <div>
          <span className="settings-page__security-tab-sub-header">
            {this.context.t('smartContracts')}
          </span>
        </div>
        <div className="settings-page__content-padded">
          {this.renderUse4ByteResolutionToggle()}
        </div>
        <span className="settings-page__security-tab-sub-header">
          {this.context.t('transactions')}
        </span>
        <div className="settings-page__content-padded">
          {this.renderCurrencyRateCheckToggle()}
          {this.renderIncomingTransactionsOptIn()}
        </div>
        <span className="settings-page__security-tab-sub-header">
          {this.context.t('networkProvider')}
        </span>
        <div className="settings-page__content-padded">
          {this.renderChooseYourNetworkButton()}
          {this.renderIpfsGatewayControl()}
        </div>
        <span className="settings-page__security-tab-sub-header">
          {this.context.t('tokenAutoDetection')}
        </span>
        <div className="settings-page__content-padded">
          {this.renderAutoDetectTokensToggle()}
          {this.renderBatchAccountBalanceRequestsToggle()}
          {this.renderOpenSeaEnabledToggle()}
          {this.renderNftDetectionToggle()}
        </div>
        <span className="settings-page__security-tab-sub-header">
          {this.context.t('metrics')}
        </span>
        <div className="settings-page__content-padded">
          {this.renderMetaMetricsOptIn()}
        </div>
      </div>
    );
  }
}