import {buildHomeBanners} from 'app/client/components/Banners';
import {makeT} from 'app/client/lib/localization';
import {AppModel} from 'app/client/models/AppModel';
import {urlState} from 'app/client/models/gristUrlState';
import {TelemetryModel, TelemetryModelImpl} from 'app/client/models/TelemetryModel';
import {AppHeader} from 'app/client/ui/AppHeader';
import {leftPanelBasic} from 'app/client/ui/LeftPanelCommon';
import {pagePanels} from 'app/client/ui/PagePanels';
import {createTopBarHome} from 'app/client/ui/TopBar';
import {cssBreadcrumbs, separator} from 'app/client/ui2018/breadcrumbs';
import {bigBasicButton, bigBasicButtonLink, bigPrimaryButton} from 'app/client/ui2018/buttons';
import {mediaSmall, theme, vars} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {cssLink} from 'app/client/ui2018/links';
import {loadingSpinner} from 'app/client/ui2018/loaders';
import {commonUrls} from 'app/common/gristUrls';
import {TelemetryPrefsWithSources} from 'app/common/InstallAPI';
import {getGristConfig} from 'app/common/urlUtils';
import {Computed, Disposable, dom, makeTestId, Observable, styled} from 'grainjs';

const testId = makeTestId('test-support-grist-page-');

const t = makeT('SupportGristPage');

export class SupportGristPage extends Disposable {
  private readonly _model: TelemetryModel = new TelemetryModelImpl(this._appModel);
  private readonly _optInToTelemetry = Computed.create(this, this._model.prefs,
    (_use, prefs) => {
      if (!prefs) { return null; }

      return prefs.telemetryLevel.value !== 'off';
    })
    .onWrite(async (optIn) => {
      const telemetryLevel = optIn ? 'limited' : 'off';
      await this._model.updateTelemetryPrefs({telemetryLevel});
    });

  constructor(private _appModel: AppModel) {
    super();
    this._model.fetchTelemetryPrefs().catch(reportError);
  }

  public buildDom() {
    const panelOpen = Observable.create(this, false);
    return pagePanels({
      leftPanel: {
        panelWidth: Observable.create(this, 240),
        panelOpen,
        hideOpener: true,
        header: dom.create(AppHeader, this._appModel.currentOrgName, this._appModel),
        content: leftPanelBasic(this._appModel, panelOpen),
      },
      headerMain: this._buildMainHeader(),
      contentTop: buildHomeBanners(this._appModel),
      contentMain: this._buildMainContent(),
    });
  }

  private _buildMainHeader() {
    return dom.frag(
      cssBreadcrumbs({style: 'margin-left: 16px;'},
        cssLink(
          urlState().setLinkUrl({}),
          t('Home'),
        ),
        separator(' / '),
        dom('span', t('Support Grist')),
      ),
      createTopBarHome(this._appModel),
    );
  }

  private _buildMainContent() {
    return cssPageContainer(
      cssPage(
        dom('div',
          cssPageTitle(t('Support Grist')),
          this._buildTelemetrySection(),
          this._buildSponsorshipSection(),
        ),
      ),
    );
  }

  private _buildTelemetrySection() {
    return cssSection(
      cssSectionTitle(t('Telemetry')),
      dom.domComputed(this._model.prefs, prefs => {
        if (prefs === null) {
          return cssSpinnerBox(loadingSpinner());
        }

        const {activation} = getGristConfig();
        if (!activation?.isManager) {
          if (prefs.telemetryLevel.value === 'limited') {
            return [
              cssParagraph(t(
                'This instance is opted in to telemetry. Only the site administrator has permission to change this.',
              ))
            ];
          } else {
            return [
              cssParagraph(t(
                'This instance is opted out of telemetry. Only the site administrator has permission to change this.',
              ))
            ];
          }
        } else {
          return [
            cssParagraph(t(
              'Support Grist by opting in to telemetry, which helps us understand how the product ' +
              'is used, so that we can prioritize future improvements.'
            )),
            cssParagraph(
              t('We only collect usage statistics, as detailed in our {{link}}, never document contents.', {
                link: telemetryHelpCenterLink(),
              }),
            ),
            cssParagraph(t('You can opt out of telemetry at any time from this page.')),
            this._buildTelemetrySectionButtons(prefs),
          ];
        }
      }),
      testId('telemetry-section'),
    );
  }

  private _buildTelemetrySectionButtons(prefs: TelemetryPrefsWithSources) {
    const {telemetryLevel: {value, source}} = prefs;
    if (source === 'preferences') {
      return dom.domComputed(this._optInToTelemetry, (optedIn) => {
        if (optedIn) {
          return [
            cssOptInOutMessage(
              t('You have opted in to telemetry. Thank you!'), ' 🙏',
              testId('telemetry-section-message'),
            ),
            cssOptOutButton(t('Opt out of Telemetry'),
              dom.on('click', () => this._optInToTelemetry.set(false)),
            ),
          ];
        } else {
          return [
            cssOptInButton(t('Opt in to Telemetry'),
              dom.on('click', () => this._optInToTelemetry.set(true)),
            ),
          ];
        }
      });
    } else {
      return cssOptInOutMessage(
        value !== 'off'
          ? [t('You have opted in to telemetry. Thank you!'), ' 🙏']
          : t('You have opted out of telemetry.'),
        testId('telemetry-section-message'),
      );
    }
  }

  private _buildSponsorshipSection() {
    return cssSection(
      cssSectionTitle(t('Sponsor Grist Labs on GitHub')),
      cssParagraph(
        t(
          'Grist software is developed by Grist Labs, which offers free and paid ' +
          'hosted plans. We also make Grist code available under a standard free ' +
          'and open OSS license (Apache 2.0) on {{link}}.',
          {link: gristCoreLink()},
        ),
      ),
      cssParagraph(
        t(
          'You can support Grist open-source development by sponsoring ' +
          'us on our {{link}}.',
          {link: sponsorGristLink()},
        ),
      ),
      cssParagraph(t(
        'We are a small and determined team. Your support matters a lot to us. ' +
        'It also shows to others that there is a determined community behind this product.'
      )),
      cssSponsorButton(
        cssButtonIconAndText(icon('Heart'), cssButtonText(t('Manage Sponsorship'))),
        {href: commonUrls.githubSponsorGristLabs, target: '_blank'},
      ),
      testId('sponsorship-section'),
    );
  }
}

function telemetryHelpCenterLink() {
  return cssLink(
    t('Help Center'),
    {href: commonUrls.helpTelemetryLimited, target: '_blank'},
  );
}

function sponsorGristLink() {
  return cssLink(
    t('GitHub Sponsors page'),
    {href: commonUrls.githubSponsorGristLabs, target: '_blank'},
  );
}

function gristCoreLink() {
  return cssLink(
    t('GitHub'),
    {href: commonUrls.githubGristCore, target: '_blank'},
  );
}

const cssPageContainer = styled('div', `
  overflow: auto;
  padding: 64px 80px;

  @media ${mediaSmall} {
    & {
      padding: 0px;
    }
  }
`);

const cssPage = styled('div', `
  padding: 16px;
  max-width: 600px;
  width: 100%;
`);

const cssPageTitle = styled('div', `
  height: 32px;
  line-height: 32px;
  margin-bottom: 24px;
  color: ${theme.text};
  font-size: 24px;
  font-weight: ${vars.headerControlTextWeight};
`);

const cssSectionTitle = styled('div', `
  height: 24px;
  line-height: 24px;
  margin-bottom: 24px;
  color: ${theme.text};
  font-size: ${vars.xlargeFontSize};
  font-weight: ${vars.headerControlTextWeight};
`);

const cssSection = styled('div', `
  margin-bottom: 60px;
`);

const cssParagraph = styled('div', `
  color: ${theme.text};
  font-size: 14px;
  line-height: 20px;
  margin-bottom: 12px;
`);

const cssOptInOutMessage = styled(cssParagraph, `
  line-height: 40px;
  font-weight: 600;
  margin-top: 24px;
  margin-bottom: 0px;
`);

const cssOptInButton = styled(bigPrimaryButton, `
  margin-top: 24px;
`);

const cssOptOutButton = styled(bigBasicButton, `
  margin-top: 24px;
`);

const cssSponsorButton = styled(bigBasicButtonLink, `
  margin-top: 24px;
`);

const cssButtonIconAndText = styled('div', `
  display: flex;
  align-items: center;
`);

const cssButtonText = styled('span', `
  margin-left: 8px;
`);

const cssSpinnerBox = styled('div', `
  margin-top: 24px;
  text-align: center;
`);