import Joi, { ValidationError } from "joi";
import { Result } from "./result";

export type TRuleValidatorResult<T> = Result<T, ValidationError>;

// biome-ignore lint/complexity/noStaticOnlyClass: <explanation>
export class RuleValidator {
  public static readonly RULE_NOT_NULL_OR_UNDEFINED = Joi.any()
    .required() // <- undefined
    .invalid(null); // <- null

  public static readonly RULE_ALLOW_NULL_OR_UNDEFINED = Joi.any()
    .optional() // <- undefined
    .valid(null); // <- null

  public static readonly RULE_ALLOW_NULL = Joi.any().valid(null); // <- null

  public static readonly RULE_ALLOW_EMPTY = Joi.any()
    .optional() // <- undefined
    .valid(null, ""); //

  public static readonly RULE_IS_TYPE_STRING = Joi.string();
  public static readonly RULE_IS_TYPE_NUMBER = Joi.number();

  public static validate<T>(
    rule: Joi.AnySchema<any> | Joi.AnySchema<any>[],
    value: any,
    options: Joi.ValidationOptions = {}
  ): TRuleValidatorResult<T> {
    if (!Joi.isSchema(rule)) {
      throw new RuleValidator_Error("Rule provided is not a valid Joi schema!");
    }

    const _options: Joi.ValidationOptions = {
      abortEarly: false,
      errors: {
        wrap: {
          label: "{}",
        },
      },
      //messages: SpanishJoiMessages,
      ...options,
    };

    const validationResult = rule.validate(value, _options);

    if (validationResult.error) {
      return Result.fail(validationResult.error);
    }

    return Result.ok<T>(validationResult.value);
  }

  public static validateFnc(ruleFnc: (value: any) => any) {
    return (value: any, helpers: any) => {
      const result = ruleFnc(value);
      return result.isSuccess
        ? value
        : helpers.message({
            custom: result.error.message,
          });
    };
  }
}

export class RuleValidator_Error extends Error {}
