import {
  ValidatorConstraint,
  ValidatorConstraintInterface,
  ValidationArguments,
  ValidationOptions,
  registerDecorator,
} from 'class-validator';
import { PostWorktypeOptionItem } from '../../features/accounts/types/types';
import { OPTION_ITEM_VALUE_TYPE } from '../../constants';

@ValidatorConstraint()
export class IsRecorderAllowedCharacters
  implements ValidatorConstraintInterface
{
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  validate(value: string) {
    if (value === '') {
      return true;
    }

    // 正規表現でWorktypeIDのチェックを行う
    // 以下の禁則文字を除く半角英数記号
    // \ (backslash)
    // / (forward slash)
    // : (colon)
    // * (asterisk)
    // ? (question mark)
    // " (double quotation mark)
    // < (less-than symbol)
    // > (greater-than symbol)
    // | (vertical bar)
    // . (period)
    const regex =
      /^(?!.*\\)(?!.*\/)(?!.*:)(?!.*\*)(?!.*\?)(?!.*")(?!.*<)(?!.*>)(?!.*\|)(?!.*\.)[ -~]+$/;
    return regex.test(value);
  }

  defaultMessage(args: ValidationArguments) {
    return `Recorder allowed characters rule not satisfied`;
  }
}

/**
 * レコーダーで使用できる文字列かをチェックする
 * @param [validationOptions]
 * @returns
 */
export function IsRecorderAllowed(validationOptions?: ValidationOptions) {
  return function (object: object, propertyName: string) {
    registerDecorator({
      name: 'IsRecorderAllowed',
      target: object.constructor,
      propertyName: propertyName,
      constraints: [],
      options: validationOptions,
      validator: IsRecorderAllowedCharacters,
    });
  };
}

@ValidatorConstraint()
export class IsNotEmptyValue implements ValidatorConstraintInterface {
  propertyName: string;
  constructor(propertyName: string) {
    this.propertyName = propertyName;
  }

  validate(value: any, args: ValidationArguments): boolean {
    const request = args.object as PostWorktypeOptionItem;
    const { itemLabel, defaultValueType } = request;

    // アイテムラベルがあり、Defaultの場合は必ず値が必要
    if (
      itemLabel !== '' &&
      defaultValueType === OPTION_ITEM_VALUE_TYPE.DEFAULT &&
      value === ''
    ) {
      return false;
    }
    return true;
  }
  defaultMessage(): string {
    return `When default value is default, ${this.propertyName} cannot be empty`;
  }
}

/**
 * 有効なオプションアイテムでDefaultの場合にinitialValueが空でないことをチェックする
 * @template T
 * @param [validationOptions]
 * @returns
 */
export function IsInitialValue(validationOptions?: ValidationOptions) {
  return (object: PostWorktypeOptionItem, propertyName: string) => {
    registerDecorator({
      name: 'IsInitialValue',
      target: object.constructor,
      propertyName: propertyName,
      constraints: [],
      options: validationOptions,
      validator: new IsNotEmptyValue(propertyName),
    });
  };
}
