import { UniqueID } from "./UniqueID";

const isEntity = (v: any): v is Entity<any> => {
  return v instanceof Entity;
};

export interface IEntityProps {
  [s: string]: any;
}

export abstract class Entity<T extends IEntityProps> {
  protected readonly _id: UniqueID;
  protected props: T;

  public get id(): UniqueID {
    return this._id;
  }

  constructor(props: T, id?: UniqueID) {
    this._id = id ? id : UniqueID.generateNewID().object;
    this.props = props;
  }

  public equals(object?: Entity<T>): boolean {
    if (object === null || object === undefined) {
      return false;
    }

    if (this === object) {
      return true;
    }

    if (!isEntity(object)) {
      return false;
    }

    return this._id.equals(object.id);
  }

  public toString(): { [s: string]: string } {
    const flattenProps = this._flattenProps(this.props);

    return {
      id: this._id.toString(),
      ...flattenProps.map((prop: any) => String(prop)),
    };
  }

  public toPrimitives(): { [s: string]: any } {
    const flattenProps = this._flattenProps(this.props);

    return {
      id: this._id.value,
      ...flattenProps,
    };
  }

  protected _flattenProps(props: T): { [s: string]: any } {
    return Object.entries(props).reduce((result: any, [key, valueObject]) => {
      console.log(key, valueObject.value);
      result[key] = valueObject.value;

      return result;
    }, {});
  }
}
