import {
  DomainError,
  IValueObjectOptions,
  Result,
  RuleValidator,
  ValueObject,
  handleDomainError,
} from "@shared/contexts";
import Joi from "joi";

export enum QUOTE_STATUS {
  DRAFT = "draft",
  READY = "ready",
  DELIVERED = "delivered",
  ACCEPTED = "accepted",
  REJECTED = "rejected",
  ARCHIVED = "archived",
}
export interface IQuoteStatusOptions extends IValueObjectOptions {}

export class QuoteStatus extends ValueObject<string> {
  public static readonly QUOTE_STATUS = QUOTE_STATUS;

  protected static validate(value: string, options: IValueObjectOptions) {
    const rule = Joi.string()
      .valid(
        QUOTE_STATUS.DRAFT,
        QUOTE_STATUS.READY,
        QUOTE_STATUS.DELIVERED,
        QUOTE_STATUS.ACCEPTED,
        QUOTE_STATUS.REJECTED,
        QUOTE_STATUS.ARCHIVED
      )
      .label(options.label ? options.label : "status");

    return RuleValidator.validate<string>(rule, value);
  }

  private static sanitize(status: string): string {
    return String(status).trim().toLowerCase();
  }

  public static createDraft(): QuoteStatus {
    return new QuoteStatus(QUOTE_STATUS.DRAFT);
  }

  public static createReady(): QuoteStatus {
    return new QuoteStatus(QUOTE_STATUS.READY);
  }

  public static createDelivered(): QuoteStatus {
    return new QuoteStatus(QUOTE_STATUS.DELIVERED);
  }

  public static createAccepted(): QuoteStatus {
    return new QuoteStatus(QUOTE_STATUS.ACCEPTED);
  }

  public static createRejected(): QuoteStatus {
    return new QuoteStatus(QUOTE_STATUS.REJECTED);
  }

  public static createArchived(): QuoteStatus {
    return new QuoteStatus(QUOTE_STATUS.ARCHIVED);
  }

  public static create(status: string, options: IQuoteStatusOptions = {}) {
    const _options = {
      label: "status",
      ...options,
    };
    const validationResult = QuoteStatus.validate(status, _options);

    if (validationResult.isFailure) {
      return Result.fail(
        handleDomainError(DomainError.INVALID_INPUT_DATA, validationResult.error.message, _options)
      );
    }

    return Result.ok(new QuoteStatus(QuoteStatus.sanitize(validationResult.object)));
  }

  get value(): string {
    return String(this.props);
  }

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

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

  public isDraft(): boolean {
    return this.equals(QuoteStatus.createDraft());
  }

  public isEmpty(): boolean {
    return this.props === "undefined";
  }
}
