import {AccountStore, Actions, IdentityStore, FolderSyncProgressStore, KeyManager} from 'nylas-exports';
import {ipcRenderer} from 'electron';
import NylasStore from 'nylas-store';

import OnboardingActions from './onboarding-actions';

function accountTypeForProvider(provider) {
  if (provider === 'eas') {
    return 'exchange';
  }
  if (provider === 'custom') {
    return 'imap';
  }
  return provider;
}

class OnboardingStore extends NylasStore {
  constructor() {
    super();

    this.listenTo(OnboardingActions.moveToPreviousPage, this._onMoveToPreviousPage)
    this.listenTo(OnboardingActions.moveToPage, this._onMoveToPage)
    this.listenTo(OnboardingActions.accountJSONReceived, this._onAccountJSONReceived)
    this.listenTo(OnboardingActions.identityJSONReceived, this._onIdentityJSONReceived)
    this.listenTo(OnboardingActions.setAccountInfo, this._onSetAccountInfo);
    this.listenTo(OnboardingActions.setAccountType, this._onSetAccountType);
    ipcRenderer.on('set-account-type', (e, type) => {
      if (type) {
        this._onSetAccountType(type)
      } else {
        this._pageStack = ['account-choose']
        this.trigger()
      }
    })

    const {existingAccount, addingAccount, accountType} = NylasEnv.getWindowProps();

    const hasAccounts = (AccountStore.accounts().length > 0)
    const identity = IdentityStore.identity();

    if (identity) {
      this._accountInfo = {
        name: `${identity.firstname || ""} ${identity.lastname || ""}`,
      };
    } else {
      this._accountInfo = {};
    }

    if (existingAccount) {
      // Used when re-adding an account after re-connecting
      const existingAccountType = accountTypeForProvider(existingAccount.provider);
      this._pageStack = ['account-choose']
      this._accountInfo = {
        name: existingAccount.name,
        email: existingAccount.emailAddress,
      };
      this._onSetAccountType(existingAccountType);
    } else if (addingAccount) {
      // Adding a new, unknown account
      this._pageStack = ['account-choose'];
      if (accountType) {
        this._onSetAccountType(accountType);
      }
    } else if (identity) {
      // Should only happen if config was edited to remove all accounts,
      // but don't want to re-login to Nylas account. Very useful when
      // switching environments.
      this._pageStack = ['account-choose'];
    } else if (hasAccounts) {
      // Should only happen when the user has "signed out" of their Nylas ID,
      // but already has accounts synced. Or is upgrading from a very old build.
      // We used to show "Welcome Back", but now just jump to sign in.
      this._pageStack = ['authenticate'];
    } else {
      // Standard new user onboarding flow.
      this._pageStack = ['welcome'];
    }
  }

  _onOnboardingComplete = () => {
    // When account JSON is received, we want to notify external services
    // that it succeeded. Unfortunately in this case we're likely to
    // close the window before those requests can be made. We add a short
    // delay here to ensure that any pending requests have a chance to
    // clear before the window closes.
    setTimeout(() => {
      ipcRenderer.send('account-setup-successful');
    }, 100);
  }

  _onSetAccountType = (type) => {
    let nextPage = "account-settings";
    if (type === 'gmail') {
      nextPage = "account-settings-gmail";
    } else if (type === 'exchange') {
      nextPage = "account-settings-exchange";
    }

    Actions.recordUserEvent('Selected Account Type', {
      provider: type,
    });

    // Don't carry over any type-specific account information
    const {email, name, password} = this._accountInfo;
    this._onSetAccountInfo({email, name, password, type});
    this._onMoveToPage(nextPage);
  }

  _onSetAccountInfo = (info) => {
    this._accountInfo = info;
    this.trigger();
  }

  _onMoveToPreviousPage = () => {
    this._pageStack.pop();
    this.trigger();
  }

  _onMoveToPage = (page) => {
    this._pageStack.push(page)
    this.trigger();
  }

  _onIdentityJSONReceived = async (json) => {
    const isFirstAccount = AccountStore.accounts().length === 0;

    await IdentityStore.saveIdentity(json);

    setTimeout(() => {
      if (isFirstAccount) {
        this._onSetAccountInfo(Object.assign({}, this._accountInfo, {
          name: `${json.firstName || ""} ${json.lastName || ""}`,
          email: json.emailAddress,
        }));
        OnboardingActions.moveToPage('account-choose');
      } else {
        this._onOnboardingComplete();
      }
    }, 1000);
  }

  _onAccountJSONReceived = async (json, cloudToken) => {
    try {
      const isFirstAccount = AccountStore.accounts().length === 0;
      const clean = KeyManager.extractAccountSecrets(json, cloudToken);
      AccountStore.addAccountFromJSON(clean);

      Actions.recordUserEvent('Email Account Auth Succeeded', {
        provider: json.provider,
      });

      ipcRenderer.send('new-account-added');
      NylasEnv.displayWindow();

      if (isFirstAccount) {
        this._onMoveToPage('initial-preferences');
        Actions.recordUserEvent('First Account Linked', {
          provider: json.provider,
        });
      } else {
        await FolderSyncProgressStore.whenCategoryListSynced(json.id)
        this._onOnboardingComplete();
      }
    } catch (e) {
      NylasEnv.reportError(e);
      NylasEnv.showErrorDialog("Unable to Connect Account", "Sorry, something went wrong on the Nylas server. Please try again. If you're still having issues, contact us at support@nylas.com.");
    }
  }

  page() {
    return this._pageStack[this._pageStack.length - 1];
  }

  pageDepth() {
    return this._pageStack.length;
  }

  accountInfo() {
    return this._accountInfo;
  }
}

export default new OnboardingStore();
