import { DomainError } from "../../../errors";
import { Result } from "../../Result";
import { ValueObject } from "../../ValueObject";
import { Order } from "./Order";
import { OrderCollection } from "./OrderCollection";

interface IOrderRootProps {
  type: string;
  items: OrderCollection;
}

export interface IOrderRoot {
  type: string;
  items: OrderCollection;

  toString(): string;
  toObject(): Record<string, any>;
}

export class OrderRoot
  extends ValueObject<IOrderRootProps>
  implements IOrderRoot
{
  public static createASC(value: Order[]): Result<IOrderRoot> {
    return this.create({
      type: "asc",
      value,
    });
  }

  public static createDESC(value: Order[]): Result<IOrderRoot> {
    return this.create({
      type: "desc",
      value,
    });
  }

  public static create(orderRootProps: any): Result<IOrderRoot> {
    // Validación de props
    const valid = this.validate(orderRootProps);
    if (valid.isFailure) {
      return Result.fail(valid.error);
    }

    return Result.ok<IOrderRoot>(
      new OrderRoot({
        type: OrderRoot.sanitizeOperator(orderRootProps.type),
        items: OrderCollection.create(orderRootProps.value),
      })
    );
  }

  protected static validate(OrderRootRoot: IOrderRootProps): Result<any> {
    throw DomainError.create("NOT IMPLEMENT", "OrderRoot.validate()");

    /*return Validator.isOneOf(
            {
                value: OrderRootRoot.type,
                valueName: 'OrderRoot root type',
            },
            ['asc', 'desc']
        );*/
  }

  protected static sanitizeOperator(type: string): string {
    return type.toUpperCase().trim();
  }

  protected _type: string;
  protected _items: OrderCollection;

  protected constructor(props: IOrderRootProps) {
    super(props);
    this._type = props.type;
    this._items = props.items;
  }

  get type(): string {
    return this._type;
  }

  get items(): OrderCollection {
    return this._items;
  }

  public toString(): string {
    return `${this.type} ${this.items.toString()}`;
  }

  public toObject(): Record<string, any> {
    return {
      type: this.type,
      items: this.items.toObject(),
    };
  }

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

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

  public transform(transformerFunction: any, params: any): any {
    return transformerFunction(this.toObject(), params);
  }
}
