/**
 * Copyright (c) 2023-present Plane Software, Inc. and contributors
 * SPDX-License-Identifier: AGPL-3.0-only
 * See the LICENSE file for details.
 */

import type { ReactNode } from "react";
// plane imports
import type { TAuthErrorInfo } from "@plane/constants";
import { E_PASSWORD_STRENGTH, EErrorAlertType, EAuthErrorCodes } from "@plane/constants";
import zxcvbn from "zxcvbn";

/**
 * @description Password strength levels
 */
export enum PasswordStrength {
  EMPTY = "empty",
  WEAK = "weak",
  FAIR = "fair",
  GOOD = "good",
  STRONG = "strong",
}

/**
 * Calculate password strength based on various criteria
 */
export const getPasswordStrength = (password: string): E_PASSWORD_STRENGTH => {
  if (!password || password === "" || password.length <= 0) {
    return E_PASSWORD_STRENGTH.EMPTY;
  }

  if (password.length < 8) {
    return E_PASSWORD_STRENGTH.LENGTH_NOT_VALID;
  }

  // Check all criteria
  const hasUpperCase = /[A-Z]/.test(password);
  const hasLowerCase = /[a-z]/.test(password);
  const hasDigit = /[0-9]/.test(password);
  const hasSpecialChar = /[!@#$%^&*()\-_+=\[\]{}|;:'",.<>?/]/.test(password);
  const isComplexEnough = hasUpperCase && hasLowerCase && hasDigit && hasSpecialChar;
  const isStrongEnough = zxcvbn(password).score >= 3;

  if (isComplexEnough && isStrongEnough) {
    return E_PASSWORD_STRENGTH.STRENGTH_VALID;
  }

  return E_PASSWORD_STRENGTH.STRENGTH_NOT_VALID;
};

export type PasswordCriteria = {
  key: string;
  label: string;
  isValid: boolean;
};

/**
 * Get password criteria for validation display
 */
export const getPasswordCriteria = (password: string): PasswordCriteria[] => [
  {
    key: "length",
    label: "Минимум 8 символов",
    isValid: password.length >= 8,
  },
  {
    key: "uppercase",
    label: "Минимум 1 заглавная буква",
    isValid: /[A-Z]/.test(password),
  },
  {
    key: "lowercase",
    label: "Минимум 1 строчная буква",
    isValid: /[a-z]/.test(password),
  },
  {
    key: "number",
    label: "Минимум 1 цифра",
    isValid: /[0-9]/.test(password),
  },
  {
    key: "special",
    label: "Минимум 1 спецсимвол",
    isValid: /[!@#$%^&*()\-_+=\[\]{}|;:'",.<>?/]/.test(password),
  },
  {
    key: "predictable",
    label: "Избегайте простых и предсказуемых шаблонов",
    isValid: password.length >= 8 ? zxcvbn(password).score >= 3 : false,
  },
];

// Error code messages
const errorCodeMessages: {
  [key in EAuthErrorCodes]: { title: string; message: (email?: string) => ReactNode };
} = {
  // global
  [EAuthErrorCodes.INSTANCE_NOT_CONFIGURED]: {
    title: `Инстанс не настроен`,
    message: () => `Инстанс не настроен. Обратитесь к администратору.`,
  },
  [EAuthErrorCodes.SIGNUP_DISABLED]: {
    title: `Регистрация отключена`,
    message: () => `Регистрация отключена. Обратитесь к администратору.`,
  },
  [EAuthErrorCodes.INVALID_PASSWORD]: {
    title: `Неверный пароль`,
    message: () => `Неверный пароль. Попробуйте снова.`,
  },
  [EAuthErrorCodes.PASSWORD_TOO_WEAK]: {
    title: `Слишком простой пароль`,
    message: () =>
      `Пароль должен содержать заглавные и строчные буквы, цифру, спецсимвол и не быть предсказуемым.`,
  },
  [EAuthErrorCodes.SMTP_NOT_CONFIGURED]: {
    title: `SMTP не настроен`,
    message: () => `SMTP не настроен. Обратитесь к администратору.`,
  },
  // email check in both sign up and sign in
  [EAuthErrorCodes.INVALID_EMAIL]: {
    title: `Некорректный e-mail`,
    message: () => `Некорректный e-mail. Попробуйте снова.`,
  },
  [EAuthErrorCodes.EMAIL_REQUIRED]: {
    title: `Нужен e-mail`,
    message: () => `Укажите e-mail и попробуйте снова.`,
  },
  // sign up
  [EAuthErrorCodes.USER_ALREADY_EXIST]: {
    title: `Аккаунт уже существует`,
    message: () => `Аккаунт уже зарегистрирован. Выполните вход.`,
  },
  [EAuthErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_UP]: {
    title: `Нужны e-mail и пароль`,
    message: () => `Укажите e-mail и пароль, затем попробуйте снова.`,
  },
  [EAuthErrorCodes.AUTHENTICATION_FAILED_SIGN_UP]: {
    title: `Не удалось выполнить вход`,
    message: () => `Не удалось выполнить вход. Проверьте данные и попробуйте снова.`,
  },
  [EAuthErrorCodes.INVALID_EMAIL_SIGN_UP]: {
    title: `Некорректный e-mail`,
    message: () => `Некорректный e-mail. Попробуйте снова.`,
  },
  [EAuthErrorCodes.MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED]: {
    title: `Нужны e-mail и код`,
    message: () => `Укажите e-mail и код подтверждения, затем попробуйте снова.`,
  },
  [EAuthErrorCodes.INVALID_EMAIL_MAGIC_SIGN_UP]: {
    title: `Некорректный e-mail`,
    message: () => `Некорректный e-mail. Попробуйте снова.`,
  },
  // sign in
  [EAuthErrorCodes.USER_ACCOUNT_DEACTIVATED]: {
    title: `Аккаунт деактивирован`,
    message: () => `Аккаунт деактивирован. Обратитесь к администратору.`,
  },
  [EAuthErrorCodes.USER_DOES_NOT_EXIST]: {
    title: `Аккаунт не найден`,
    message: () => `Аккаунт не найден. Создайте новый для начала работы.`,
  },
  [EAuthErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_IN]: {
    title: `Нужны e-mail и пароль`,
    message: () => `Укажите e-mail и пароль, затем попробуйте снова.`,
  },
  [EAuthErrorCodes.AUTHENTICATION_FAILED_SIGN_IN]: {
    title: `Не удалось выполнить вход`,
    message: () => `Не удалось выполнить вход. Проверьте данные и попробуйте снова.`,
  },
  [EAuthErrorCodes.INVALID_EMAIL_SIGN_IN]: {
    title: `Некорректный e-mail`,
    message: () => `Некорректный e-mail. Попробуйте снова.`,
  },
  [EAuthErrorCodes.MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED]: {
    title: `Нужны e-mail и код`,
    message: () => `Укажите e-mail и код подтверждения, затем попробуйте снова.`,
  },
  [EAuthErrorCodes.INVALID_EMAIL_MAGIC_SIGN_IN]: {
    title: `Некорректный e-mail`,
    message: () => `Некорректный e-mail. Попробуйте снова.`,
  },
  // Both Sign in and Sign up
  [EAuthErrorCodes.INVALID_MAGIC_CODE_SIGN_IN]: {
    title: `Неверный код подтверждения`,
    message: () => `Неверный код подтверждения. Попробуйте снова.`,
  },
  [EAuthErrorCodes.INVALID_MAGIC_CODE_SIGN_UP]: {
    title: `Неверный код подтверждения`,
    message: () => `Неверный код подтверждения. Попробуйте снова.`,
  },
  [EAuthErrorCodes.EXPIRED_MAGIC_CODE_SIGN_IN]: {
    title: `Код подтверждения истёк`,
    message: () => `Код подтверждения истёк. Запросите новый и попробуйте снова.`,
  },
  [EAuthErrorCodes.EXPIRED_MAGIC_CODE_SIGN_UP]: {
    title: `Код подтверждения истёк`,
    message: () => `Код подтверждения истёк. Запросите новый и попробуйте снова.`,
  },
  [EAuthErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_IN]: {
    title: `Лимит попыток исчерпан`,
    message: () => `Лимит попыток ввода кода исчерпан. Запросите новый код.`,
  },
  [EAuthErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_UP]: {
    title: `Лимит попыток исчерпан`,
    message: () => `Лимит попыток ввода кода исчерпан. Запросите новый код.`,
  },
  // Oauth
  [EAuthErrorCodes.OAUTH_NOT_CONFIGURED]: {
    title: `OAuth не настроен`,
    message: () => `OAuth не настроен. Обратитесь к администратору.`,
  },
  [EAuthErrorCodes.GOOGLE_NOT_CONFIGURED]: {
    title: `Google OAuth не настроен`,
    message: () => `Google OAuth не настроен. Обратитесь к администратору.`,
  },
  [EAuthErrorCodes.GITHUB_NOT_CONFIGURED]: {
    title: `GitHub OAuth не настроен`,
    message: () => `GitHub OAuth не настроен. Обратитесь к администратору.`,
  },
  [EAuthErrorCodes.GITLAB_NOT_CONFIGURED]: {
    title: `GitLab OAuth не настроен`,
    message: () => `GitLab OAuth не настроен. Обратитесь к администратору.`,
  },
  [EAuthErrorCodes.GOOGLE_OAUTH_PROVIDER_ERROR]: {
    title: `Ошибка Google OAuth`,
    message: () => `Не удалось авторизоваться через Google. Попробуйте снова.`,
  },
  [EAuthErrorCodes.GITHUB_OAUTH_PROVIDER_ERROR]: {
    title: `Ошибка GitHub OAuth`,
    message: () => `Не удалось авторизоваться через GitHub. Попробуйте снова.`,
  },
  [EAuthErrorCodes.GITLAB_OAUTH_PROVIDER_ERROR]: {
    title: `Ошибка GitLab OAuth`,
    message: () => `Не удалось авторизоваться через GitLab. Попробуйте снова.`,
  },
  // Reset Password
  [EAuthErrorCodes.INVALID_PASSWORD_TOKEN]: {
    title: `Некорректный токен`,
    message: () => `Некорректный токен восстановления. Попробуйте снова.`,
  },
  [EAuthErrorCodes.EXPIRED_PASSWORD_TOKEN]: {
    title: `Токен истёк`,
    message: () => `Токен восстановления истёк. Запросите новый.`,
  },
  // Change password
  [EAuthErrorCodes.MISSING_PASSWORD]: {
    title: `Нужен пароль`,
    message: () => `Укажите пароль и попробуйте снова.`,
  },
  [EAuthErrorCodes.INCORRECT_OLD_PASSWORD]: {
    title: `Неверный старый пароль`,
    message: () => `Старый пароль указан неверно. Попробуйте снова.`,
  },
  [EAuthErrorCodes.INVALID_NEW_PASSWORD]: {
    title: `Некорректный новый пароль`,
    message: () => `Новый пароль не соответствует требованиям.`,
  },
  // set password
  [EAuthErrorCodes.PASSWORD_ALREADY_SET]: {
    title: `Пароль уже установлен`,
    message: () => `Пароль уже установлен. Выполните вход.`,
  },
  // admin
  [EAuthErrorCodes.ADMIN_ALREADY_EXIST]: {
    title: `Администратор уже существует`,
    message: () => `Администратор уже существует. Попробуйте снова.`,
  },
  [EAuthErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME]: {
    title: `Нужны e-mail, пароль и имя`,
    message: () => `Укажите e-mail, пароль и имя, затем попробуйте снова.`,
  },
  [EAuthErrorCodes.INVALID_ADMIN_EMAIL]: {
    title: `Некорректный e-mail администратора`,
    message: () => `Некорректный e-mail администратора. Попробуйте снова.`,
  },
  [EAuthErrorCodes.INVALID_ADMIN_PASSWORD]: {
    title: `Некорректный пароль администратора`,
    message: () => `Некорректный пароль администратора. Попробуйте снова.`,
  },
  [EAuthErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD]: {
    title: `Нужны e-mail и пароль`,
    message: () => `Укажите e-mail и пароль, затем попробуйте снова.`,
  },
  [EAuthErrorCodes.ADMIN_AUTHENTICATION_FAILED]: {
    title: `Не удалось выполнить вход`,
    message: () => `Не удалось выполнить вход. Проверьте данные и попробуйте снова.`,
  },
  [EAuthErrorCodes.ADMIN_USER_ALREADY_EXIST]: {
    title: `Администратор уже существует`,
    message: () => `Администратор уже существует. Выполните вход.`,
  },
  [EAuthErrorCodes.ADMIN_USER_DOES_NOT_EXIST]: {
    title: `Администратор не найден`,
    message: () => `Администратор не найден. Выполните вход.`,
  },
  [EAuthErrorCodes.MAGIC_LINK_LOGIN_DISABLED]: {
    title: `Вход по magic link отключён`,
    message: () => `Вход по magic link отключён. Используйте пароль.`,
  },
  [EAuthErrorCodes.PASSWORD_LOGIN_DISABLED]: {
    title: `Вход по паролю отключён`,
    message: () => `Вход по паролю отключён. Используйте magic link.`,
  },
  [EAuthErrorCodes.ADMIN_USER_DEACTIVATED]: {
    title: `Администратор деактивирован`,
    message: () => `Аккаунт администратора деактивирован. Обратитесь к администратору.`,
  },
  [EAuthErrorCodes.RATE_LIMIT_EXCEEDED]: {
    title: `Слишком много запросов`,
    message: () => `Слишком много запросов. Повторите попытку позже.`,
  },
};

// Error handler
export const authErrorHandler = (errorCode: EAuthErrorCodes, email?: string): TAuthErrorInfo | undefined => {
  const bannerAlertErrorCodes = [
    EAuthErrorCodes.INSTANCE_NOT_CONFIGURED,
    EAuthErrorCodes.INVALID_EMAIL,
    EAuthErrorCodes.EMAIL_REQUIRED,
    EAuthErrorCodes.SIGNUP_DISABLED,
    EAuthErrorCodes.INVALID_PASSWORD,
    EAuthErrorCodes.SMTP_NOT_CONFIGURED,
    EAuthErrorCodes.USER_ALREADY_EXIST,
    EAuthErrorCodes.AUTHENTICATION_FAILED_SIGN_UP,
    EAuthErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_UP,
    EAuthErrorCodes.INVALID_EMAIL_SIGN_UP,
    EAuthErrorCodes.INVALID_EMAIL_MAGIC_SIGN_UP,
    EAuthErrorCodes.MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED,
    EAuthErrorCodes.USER_DOES_NOT_EXIST,
    EAuthErrorCodes.AUTHENTICATION_FAILED_SIGN_IN,
    EAuthErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_IN,
    EAuthErrorCodes.INVALID_EMAIL_SIGN_IN,
    EAuthErrorCodes.INVALID_EMAIL_MAGIC_SIGN_IN,
    EAuthErrorCodes.MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED,
    EAuthErrorCodes.INVALID_MAGIC_CODE_SIGN_IN,
    EAuthErrorCodes.INVALID_MAGIC_CODE_SIGN_UP,
    EAuthErrorCodes.EXPIRED_MAGIC_CODE_SIGN_IN,
    EAuthErrorCodes.EXPIRED_MAGIC_CODE_SIGN_UP,
    EAuthErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_IN,
    EAuthErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_UP,
    EAuthErrorCodes.OAUTH_NOT_CONFIGURED,
    EAuthErrorCodes.GOOGLE_NOT_CONFIGURED,
    EAuthErrorCodes.GITHUB_NOT_CONFIGURED,
    EAuthErrorCodes.GITLAB_NOT_CONFIGURED,
    EAuthErrorCodes.GOOGLE_OAUTH_PROVIDER_ERROR,
    EAuthErrorCodes.GITHUB_OAUTH_PROVIDER_ERROR,
    EAuthErrorCodes.GITLAB_OAUTH_PROVIDER_ERROR,
    EAuthErrorCodes.INVALID_PASSWORD_TOKEN,
    EAuthErrorCodes.EXPIRED_PASSWORD_TOKEN,
    EAuthErrorCodes.INCORRECT_OLD_PASSWORD,
    EAuthErrorCodes.INVALID_NEW_PASSWORD,
    EAuthErrorCodes.PASSWORD_ALREADY_SET,
    EAuthErrorCodes.ADMIN_ALREADY_EXIST,
    EAuthErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME,
    EAuthErrorCodes.INVALID_ADMIN_EMAIL,
    EAuthErrorCodes.INVALID_ADMIN_PASSWORD,
    EAuthErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD,
    EAuthErrorCodes.ADMIN_AUTHENTICATION_FAILED,
    EAuthErrorCodes.ADMIN_USER_ALREADY_EXIST,
    EAuthErrorCodes.ADMIN_USER_DOES_NOT_EXIST,
    EAuthErrorCodes.USER_ACCOUNT_DEACTIVATED,
  ];

  if (bannerAlertErrorCodes.includes(errorCode))
    return {
      type: EErrorAlertType.BANNER_ALERT,
      code: errorCode,
      title: errorCodeMessages[errorCode]?.title || "Ошибка",
      message: errorCodeMessages[errorCode]?.message(email) || "Что-то пошло не так. Попробуйте снова.",
    };

  return undefined;
};
