import Joi from "joi";
import { UndefinedOr } from "../../../../../../utilities";
import { RuleValidator } from "../../../RuleValidator";
import { Result } from "../../Result";
import { ValueObject } from "../../ValueObject";

export interface IQuickSearchCriteria {
  searchTerms: string[];
  isEmpty(): boolean;
  toStringArray(): string[];
  toString(): string;
  toJSON(): string;
  toPrimitive(): string;
}

export class QuickSearchCriteria
  extends ValueObject<UndefinedOr<string[]>>
  implements IQuickSearchCriteria
{
  protected static validate(value: UndefinedOr<string[]>) {
    const searchStringArray = value;
    const schema = Joi.array().items(Joi.string().trim().allow("")).default([]);

    const stringArrayOrError = RuleValidator.validate<string[]>(schema, searchStringArray);

    if (stringArrayOrError.isFailure) {
      return stringArrayOrError;
    }

    return Result.ok(searchStringArray);
  }

  public static create(value: UndefinedOr<string[]>) {
    const stringArrayOrError = this.validate(value);

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

    const sanitizedTerms = QuickSearchCriteria.sanitize(stringArrayOrError.object);

    return Result.ok<QuickSearchCriteria>(new QuickSearchCriteria(sanitizedTerms));
  }

  private static sanitize(terms: string[] | undefined): string[] {
    return terms ? terms.map((term) => term.trim()).filter((term) => term.length > 0) : [];
  }

  get value(): UndefinedOr<string[]> {
    return !this.isEmpty() ? this.props : undefined;
  }

  get searchTerms(): string[] {
    return this.toStringArray();
  }

  public isEmpty = (): boolean => {
    return this.props ? this.props.length === 0 : true;
  };

  public toStringArray = (): string[] => {
    return this.props ? [...this.props] : [];
  };

  public toString = (): string => {
    return this.toStringArray().toString();
  };

  public toJSON(): string {
    return JSON.stringify(this.toStringArray());
  }

  public toPrimitive(): string {
    return this.toString();
  }
}
