import getURL from "discourse-common/lib/get-url";
import I18n from "I18n";
import { not, or, gt } from "@ember/object/computed";
import Controller from "@ember/controller";
import { iconHTML } from "discourse-common/lib/icon-library";
import CanCheckEmails from "discourse/mixins/can-check-emails";
import discourseComputed from "discourse-common/utils/decorators";
import { propertyNotEqual, setting } from "discourse/lib/computed";
import { popupAjaxError } from "discourse/lib/ajax-error";
import showModal from "discourse/lib/show-modal";
import { findAll } from "discourse/models/login-method";
import { ajax } from "discourse/lib/ajax";
import { userPath } from "discourse/lib/url";
import logout from "discourse/lib/logout";
import EmberObject from "@ember/object";
import bootbox from "bootbox";

// Number of tokens shown by default.
const DEFAULT_AUTH_TOKENS_COUNT = 2;

export default Controller.extend(CanCheckEmails, {
  init() {
    this._super(...arguments);

    this.saveAttrNames = ["name", "title", "primary_group_id"];
    this.set("revoking", {});
  },

  canEditName: setting("enable_names"),
  canSaveUser: true,

  newNameInput: null,
  newTitleInput: null,
  newPrimaryGroupInput: null,

  passwordProgress: null,

  showAllAuthTokens: false,

  revoking: null,

  cannotDeleteAccount: not("currentUser.can_delete_account"),
  deleteDisabled: or("model.isSaving", "deleting", "cannotDeleteAccount"),

  reset() {
    this.set("passwordProgress", null);
  },

  @discourseComputed()
  nameInstructions() {
    return I18n.t(
      this.siteSettings.full_name_required
        ? "user.name.instructions_required"
        : "user.name.instructions"
    );
  },

  canSelectTitle: gt("model.availableTitles.length", 0),

  @discourseComputed("model.filteredGroups")
  canSelectPrimaryGroup(primaryGroupOptions) {
    return (
      primaryGroupOptions.length > 0 &&
      this.siteSettings.user_selected_primary_groups
    );
  },

  @discourseComputed("model.is_anonymous")
  canChangePassword(isAnonymous) {
    if (isAnonymous) {
      return false;
    } else {
      return (
        !this.siteSettings.enable_sso && this.siteSettings.enable_local_logins
      );
    }
  },

  @discourseComputed("model.associated_accounts")
  associatedAccountsLoaded(associatedAccounts) {
    return typeof associatedAccounts !== "undefined";
  },

  @discourseComputed("model.associated_accounts.[]")
  authProviders(accounts) {
    const allMethods = findAll();

    const result = allMethods.map((method) => {
      return {
        method,
        account: accounts.find((account) => account.name === method.name), // Will be undefined if no account
      };
    });

    return result.filter((value) => value.account || value.method.can_connect);
  },

  disableConnectButtons: propertyNotEqual("model.id", "currentUser.id"),

  @discourseComputed(
    "model.email",
    "model.secondary_emails.[]",
    "model.unconfirmed_emails.[]"
  )
  emails(primaryEmail, secondaryEmails, unconfirmedEmails) {
    const emails = [];

    if (primaryEmail) {
      emails.push(
        EmberObject.create({
          email: primaryEmail,
          primary: true,
          confirmed: true,
        })
      );
    }

    if (secondaryEmails) {
      secondaryEmails.forEach((email) => {
        emails.push(EmberObject.create({ email, confirmed: true }));
      });
    }

    if (unconfirmedEmails) {
      unconfirmedEmails.forEach((email) => {
        emails.push(EmberObject.create({ email }));
      });
    }

    return emails.sort((a, b) => a.email.localeCompare(b.email));
  },

  @discourseComputed(
    "model.second_factor_enabled",
    "canCheckEmails",
    "model.is_anonymous"
  )
  canUpdateAssociatedAccounts(
    secondFactorEnabled,
    canCheckEmails,
    isAnonymous
  ) {
    if (secondFactorEnabled || !canCheckEmails || isAnonymous) {
      return false;
    }
    return findAll().length > 0;
  },

  @discourseComputed("showAllAuthTokens", "model.user_auth_tokens")
  authTokens(showAllAuthTokens, tokens) {
    tokens.sort((a, b) => {
      if (a.is_active) {
        return -1;
      } else if (b.is_active) {
        return 1;
      } else {
        return b.seen_at.localeCompare(a.seen_at);
      }
    });

    return showAllAuthTokens
      ? tokens
      : tokens.slice(0, DEFAULT_AUTH_TOKENS_COUNT);
  },

  canShowAllAuthTokens: gt(
    "model.user_auth_tokens.length",
    DEFAULT_AUTH_TOKENS_COUNT
  ),

  actions: {
    save() {
      this.set("saved", false);

      this.model.setProperties({
        name: this.newNameInput,
        title: this.newTitleInput,
        primary_group_id: this.newPrimaryGroupInput,
      });

      return this.model
        .save(this.saveAttrNames)
        .then(() => this.set("saved", true))
        .catch(popupAjaxError);
    },

    setPrimaryEmail(email) {
      this.model.setPrimaryEmail(email).catch(popupAjaxError);
    },

    destroyEmail(email) {
      this.model.destroyEmail(email);
    },

    resendConfirmationEmail(email) {
      email.set("resending", true);
      this.model
        .addEmail(email.email)
        .then(() => {
          email.set("resent", true);
        })
        .finally(() => {
          email.set("resending", false);
        });
    },

    changePassword() {
      if (!this.passwordProgress) {
        this.set(
          "passwordProgress",
          I18n.t("user.change_password.in_progress")
        );
        return this.model
          .changePassword()
          .then(() => {
            // password changed
            this.setProperties({
              changePasswordProgress: false,
              passwordProgress: I18n.t("user.change_password.success"),
            });
          })
          .catch(() => {
            // password failed to change
            this.setProperties({
              changePasswordProgress: false,
              passwordProgress: I18n.t("user.change_password.error"),
            });
          });
      }
    },

    delete() {
      this.set("deleting", true);
      const message = I18n.t("user.delete_account_confirm"),
        model = this.model,
        buttons = [
          {
            label: I18n.t("cancel"),
            class: "d-modal-cancel",
            link: true,
            callback: () => {
              this.set("deleting", false);
            },
          },
          {
            label:
              iconHTML("exclamation-triangle") + I18n.t("user.delete_account"),
            class: "btn btn-danger",
            callback() {
              model.delete().then(
                () => {
                  bootbox.alert(
                    I18n.t("user.deleted_yourself"),
                    () => (window.location = getURL("/"))
                  );
                },
                () => {
                  bootbox.alert(I18n.t("user.delete_yourself_not_allowed"));
                  this.set("deleting", false);
                }
              );
            },
          },
        ];
      bootbox.dialog(message, buttons, { classes: "delete-account" });
    },

    revokeAccount(account) {
      this.set(`revoking.${account.name}`, true);

      this.model
        .revokeAssociatedAccount(account.name)
        .then((result) => {
          if (result.success) {
            this.model.associated_accounts.removeObject(account);
          } else {
            bootbox.alert(result.message);
          }
        })
        .catch(popupAjaxError)
        .finally(() => this.set(`revoking.${account.name}`, false));
    },

    toggleShowAllAuthTokens() {
      this.toggleProperty("showAllAuthTokens");
    },

    revokeAuthToken(token) {
      ajax(
        userPath(
          `${this.get("model.username_lower")}/preferences/revoke-auth-token`
        ),
        {
          type: "POST",
          data: token ? { token_id: token.id } : {},
        }
      )
        .then(() => {
          if (!token) logout(); // All sessions revoked
        })
        .catch(popupAjaxError);
    },

    showToken(token) {
      showModal("auth-token", { model: token });
    },

    connectAccount(method) {
      method.doLogin({ reconnect: true });
    },
  },
});
