import { UndefinedOr } from "../../../../../../utilities";
import { RuleValidator } from "../../../RuleValidator";
import { Result } from "../../Result";
import { ResultCollection } from "../../ResultCollection";
import { StringValueObject } from "../../StringValueObject";

export interface IFieldCriteria {
  toJSON(): string;
  toString(): string;
  toObject(): Record<string, any>;
}

export class FieldCriteria extends StringValueObject implements IFieldCriteria {
  public static create(value: UndefinedOr<string>) {
    const validatedProps = this.validate(value);

    if (validatedProps.isFailure) {
      return Result.fail(validatedProps.error);
    }

    return Result.ok<FieldCriteria>(new FieldCriteria(String(value)));
  }

  protected static validate(value: UndefinedOr<string>) {
    if (RuleValidator.validate(RuleValidator.RULE_NOT_NULL_OR_UNDEFINED, value).isSuccess) {
      const stringOrError = RuleValidator.validate(RuleValidator.RULE_IS_TYPE_STRING, value);

      if (stringOrError.isFailure) {
        return stringOrError;
      }
    }

    const fieldString = String(value);

    const fieldsOrErrors = new ResultCollection();

    this.parseFieldString(fieldString).forEach((token: string[]) => {
      const fieldOrError = Field.create({
        field: token[2],
        operator: String(token[3]).toUpperCase(),
        value: token[4],
      });

      fieldsOrErrors.add(fieldOrError);
    });

    if (fieldsOrErrors.hasSomeFaultyResult()) {
      return fieldsOrErrors.getFirstFaultyResult() as Result<never, Error>;
    }

    return Result.ok(fieldString);
  }
}
