import styled from '@emotion/styled';

import {addErrorMessage, addSuccessMessage} from 'sentry/actionCreators/indicator';
import {openModal} from 'sentry/actionCreators/modal';
import {
  installSentryApp,
  uninstallSentryApp,
} from 'sentry/actionCreators/sentryAppInstallations';
import AsyncComponent from 'sentry/components/asyncComponent';
import {Button} from 'sentry/components/button';
import CircleIndicator from 'sentry/components/circleIndicator';
import Confirm from 'sentry/components/confirm';
import SentryAppIcon from 'sentry/components/sentryAppIcon';
import {IconSubtract} from 'sentry/icons';
import {t, tct} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import {IntegrationFeature, SentryApp, SentryAppInstallation} from 'sentry/types';
import {toPermissions} from 'sentry/utils/consolidatedScopes';
import {getSentryAppInstallStatus} from 'sentry/utils/integrationUtil';
import {addQueryParamsToExistingUrl} from 'sentry/utils/queryString';
import {recordInteraction} from 'sentry/utils/recordSentryAppInteraction';
import withOrganization from 'sentry/utils/withOrganization';

import AbstractIntegrationDetailedView from './abstractIntegrationDetailedView';
import {SplitInstallationIdModal} from './SplitInstallationIdModal';

type State = {
  appInstalls: SentryAppInstallation[];
  featureData: IntegrationFeature[];
  sentryApp: SentryApp;
};

type Tab = AbstractIntegrationDetailedView['state']['tab'];

class SentryAppDetailedView extends AbstractIntegrationDetailedView<
  AbstractIntegrationDetailedView['props'],
  State & AbstractIntegrationDetailedView['state']
> {
  tabs: Tab[] = ['overview'];
  getEndpoints(): ReturnType<AsyncComponent['getEndpoints']> {
    const {
      organization,
      params: {integrationSlug},
    } = this.props;
    return [
      ['sentryApp', `/sentry-apps/${integrationSlug}/`],
      ['featureData', `/sentry-apps/${integrationSlug}/features/`],
      ['appInstalls', `/organizations/${organization.slug}/sentry-app-installations/`],
    ];
  }

  onLoadAllEndpointsSuccess() {
    const {
      organization,
      params: {integrationSlug},
      router,
    } = this.props;

    // redirect for internal integrations
    if (this.sentryApp.status === 'internal') {
      router.push(
        `/settings/${organization.slug}/developer-settings/${integrationSlug}/`
      );
      return;
    }

    super.onLoadAllEndpointsSuccess();
    recordInteraction(integrationSlug, 'sentry_app_viewed');
  }

  get integrationType() {
    return 'sentry_app' as const;
  }

  get sentryApp() {
    return this.state.sentryApp;
  }

  get description() {
    return this.state.sentryApp.overview || '';
  }

  get author() {
    return this.sentryApp.author;
  }

  get resourceLinks() {
    // only show links for published sentry apps
    if (this.sentryApp.status !== 'published') {
      return [];
    }
    return [
      {
        title: 'Documentation',
        url: `https://docs.sentry.io/product/integrations/${this.integrationSlug}/`,
      },
    ];
  }

  get permissions() {
    return toPermissions(this.sentryApp.scopes);
  }

  get installationStatus() {
    return getSentryAppInstallStatus(this.install);
  }

  get integrationName() {
    return this.sentryApp.name;
  }

  get featureData() {
    return this.state.featureData;
  }

  get install() {
    return this.state.appInstalls.find(i => i.app.slug === this.sentryApp.slug);
  }

  redirectUser = (install: SentryAppInstallation) => {
    const {organization} = this.props;
    const {sentryApp} = this.state;
    const queryParams = {
      installationId: install.uuid,
      code: install.code,
      orgSlug: organization.slug,
    };
    if (sentryApp.redirectUrl) {
      const redirectUrl = addQueryParamsToExistingUrl(sentryApp.redirectUrl, queryParams);
      window.location.assign(redirectUrl);
    }
  };

  handleInstall = async () => {
    const {organization} = this.props;
    const {sentryApp} = this.state;
    this.trackIntegrationAnalytics('integrations.installation_start', {
      integration_status: sentryApp.status,
    });
    // installSentryApp adds a message on failure
    const install = await installSentryApp(this.api, organization.slug, sentryApp);

    // installation is complete if the status is installed
    if (install.status === 'installed') {
      this.trackIntegrationAnalytics('integrations.installation_complete', {
        integration_status: sentryApp.status,
      });
    }

    if (!sentryApp.redirectUrl) {
      addSuccessMessage(t('%s successfully installed.', sentryApp.slug));
      this.setState({appInstalls: [install, ...this.state.appInstalls]});

      // hack for split so we can show the install ID to users for them to copy
      // Will remove once the proper fix is in place
      if (['split', 'split-dev', 'split-testing'].includes(sentryApp.slug)) {
        openModal(({closeModal}) => (
          <SplitInstallationIdModal
            installationId={install.uuid}
            closeModal={closeModal}
          />
        ));
      }
    } else {
      this.redirectUser(install);
    }
  };

  handleUninstall = async (install: SentryAppInstallation) => {
    try {
      await uninstallSentryApp(this.api, install);
      this.trackIntegrationAnalytics('integrations.uninstall_completed', {
        integration_status: this.sentryApp.status,
      });
      const appInstalls = this.state.appInstalls.filter(
        i => i.app.slug !== this.sentryApp.slug
      );
      return this.setState({appInstalls});
    } catch (error) {
      return addErrorMessage(t('Unable to uninstall %s', this.sentryApp.name));
    }
  };

  recordUninstallClicked = () => {
    const sentryApp = this.sentryApp;
    this.trackIntegrationAnalytics('integrations.uninstall_clicked', {
      integration_status: sentryApp.status,
    });
  };

  renderPermissions() {
    const permissions = this.permissions;
    if (!Object.keys(permissions).some(scope => permissions[scope].length > 0)) {
      return null;
    }

    return (
      <PermissionWrapper>
        <Title>Permissions</Title>
        {permissions.read.length > 0 && (
          <Permission>
            <Indicator />
            <Text key="read">
              {tct('[read] access to [resources] resources', {
                read: <strong>Read</strong>,
                resources: permissions.read.join(', '),
              })}
            </Text>
          </Permission>
        )}
        {permissions.write.length > 0 && (
          <Permission>
            <Indicator />
            <Text key="write">
              {tct('[read] and [write] access to [resources] resources', {
                read: <strong>Read</strong>,
                write: <strong>Write</strong>,
                resources: permissions.write.join(', '),
              })}
            </Text>
          </Permission>
        )}
        {permissions.admin.length > 0 && (
          <Permission>
            <Indicator />
            <Text key="admin">
              {tct('[admin] access to [resources] resources', {
                admin: <strong>Admin</strong>,
                resources: permissions.admin.join(', '),
              })}
            </Text>
          </Permission>
        )}
      </PermissionWrapper>
    );
  }

  renderTopButton(disabledFromFeatures: boolean, userHasAccess: boolean) {
    const install = this.install;
    const capitalizedSlug =
      this.integrationSlug.charAt(0).toUpperCase() + this.integrationSlug.slice(1);
    if (install) {
      return (
        <Confirm
          disabled={!userHasAccess}
          message={tct('Are you sure you want to uninstall the [slug] installation?', {
            slug: capitalizedSlug,
          })}
          onConfirm={() => this.handleUninstall(install)} // called when the user confirms the action
          onConfirming={this.recordUninstallClicked} // called when the confirm modal opens
          priority="danger"
        >
          <StyledUninstallButton size="sm" data-test-id="sentry-app-uninstall">
            <IconSubtract isCircled style={{marginRight: space(0.75)}} />
            {t('Uninstall')}
          </StyledUninstallButton>
        </Confirm>
      );
    }

    if (userHasAccess) {
      return (
        <InstallButton
          data-test-id="install-button"
          disabled={disabledFromFeatures}
          onClick={() => this.handleInstall()}
          priority="primary"
          size="sm"
          style={{marginLeft: space(1)}}
        >
          {t('Accept & Install')}
        </InstallButton>
      );
    }

    return this.renderRequestIntegrationButton();
  }

  // no configurations for sentry apps
  renderConfigurations() {
    return null;
  }

  renderIntegrationIcon() {
    return <SentryAppIcon sentryApp={this.sentryApp} size={50} />;
  }
}

const Text = styled('p')`
  margin: 0px 6px;
`;

const Permission = styled('div')`
  display: flex;
`;

const PermissionWrapper = styled('div')`
  padding-bottom: ${space(2)};
`;

const Title = styled('p')`
  margin-bottom: ${space(1)};
  font-weight: bold;
`;

const Indicator = styled(p => <CircleIndicator size={7} {...p} />)`
  align-self: center;
  color: ${p => p.theme.success};
`;

const InstallButton = styled(Button)`
  margin-left: ${space(1)};
`;

const StyledUninstallButton = styled(Button)`
  color: ${p => p.theme.gray300};
  background: ${p => p.theme.background};

  border: ${p => `1px solid ${p.theme.gray300}`};
  box-sizing: border-box;
  box-shadow: 0px 2px 1px rgba(0, 0, 0, 0.08);
  border-radius: 4px;
`;

export default withOrganization(SentryAppDetailedView);
