import CryptoJS from 'crypto-js';
import { StringUtil, CharactorType } from '@ucap-webmessenger/core';

export interface PasswordValidationOption {
  userId?: string;
  phoneNumber?: string;
}

export enum PasswordValidationResult {
  Valid = 'Valid',
  Empty = 'Empty',
  IncludeUserId = 'IncludeUserId',
  IncludePhoneNumber = 'IncludePhoneNumber',
  IncludeSpace = 'IncludeSpace',
  IncludeRepeated = 'IncludeRepeated',
  IncludeIncrements = 'IncludeIncrements',
  IncludeDecrements = 'IncludeDecrements',
  LackOfCombination = 'LackOfCombination',
  TooShortCombinationLength = 'TooShortCombinationLength'
}

export class PasswordUtil {
  static encrypt(password: string): string {
    return CryptoJS.enc.Hex.stringify(CryptoJS.SHA256(password));
  }

  static validate(
    password: string,
    option?: PasswordValidationOption
  ): { code: PasswordValidationResult; extra?: any } {
    if (!password || '' === password.trim()) {
      return {
        code: PasswordValidationResult.Empty
      };
    }

    if (!!option && !!option.userId) {
      if (-1 < password.indexOf(option.userId)) {
        return {
          code: PasswordValidationResult.IncludeUserId
        };
      }
    }

    if (!!option && !!option.phoneNumber) {
      const phoneNumberOnly = option.phoneNumber
        .trim()
        .replace(new RegExp('-', 'g'), '');

      switch (phoneNumberOnly.length) {
        case 11:
          if (-1 < password.indexOf(phoneNumberOnly.substr(3, 4))) {
            return {
              code: PasswordValidationResult.IncludePhoneNumber
            };
          }
          if (-1 < password.indexOf(phoneNumberOnly.substr(7, 4))) {
            return {
              code: PasswordValidationResult.IncludePhoneNumber
            };
          }
          break;
        case 10:
          if (-1 < password.indexOf(phoneNumberOnly.substr(3, 3))) {
            return {
              code: PasswordValidationResult.IncludePhoneNumber
            };
          }
          if (-1 < password.indexOf(phoneNumberOnly.substr(6, 4))) {
            return {
              code: PasswordValidationResult.IncludePhoneNumber
            };
          }
          break;
        default:
          break;
      }
    }

    if (0 < StringUtil.includes(password, CharactorType.Space)) {
      return {
        code: PasswordValidationResult.IncludeSpace
      };
    }
    if (StringUtil.isRepeat(password, 3)) {
      return {
        code: PasswordValidationResult.IncludeRepeated
      };
    }
    if (StringUtil.isIncrements(password, 3)) {
      return {
        code: PasswordValidationResult.IncludeIncrements
      };
    }
    if (StringUtil.isDecrements(password, 3)) {
      return {
        code: PasswordValidationResult.IncludeDecrements
      };
    }

    let combinationCount = 0;
    if (0 < StringUtil.includes(password, CharactorType.Special)) {
      combinationCount++;
    }
    if (0 < StringUtil.includes(password, CharactorType.Number)) {
      combinationCount++;
    }
    if (0 < StringUtil.includes(password, CharactorType.Charactor)) {
      combinationCount++;
    }

    let minPwLen = 0;
    if (2 < combinationCount) {
      minPwLen = 8;
    } else if (2 === combinationCount) {
      minPwLen = 10;
    } else if (2 > combinationCount) {
      return {
        code: PasswordValidationResult.LackOfCombination
      };
    }

    if (password.length < minPwLen) {
      return {
        code: PasswordValidationResult.TooShortCombinationLength,
        extra: {
          combinationCount,
          minPwLen
        }
      };
    }

    return {
      code: PasswordValidationResult.Valid
    };
  }
}
