import { v4 as uuid } from "uuid";

export default class Location {
  public id: string;

  public constructor(
    public name: string,
    public lat: number,
    public lon: number
  ) {
    this.id = uuid();
  }
}

// class LocationService {
//   public setLocation(id: string, name: string) {
//     const location: Location = (location.name = name); // tirer du repository
//   }
// }

class Money {
  public readonly value: number;
  public readonly currency: string;

  constructor(value: number, currency: string) {
    if (value < 0) {
      throw new Error("le prix doit être positif");
    }

    this.value = value;
    this.currency = currency;
  }

  public add(amount: Money): Money {
    if (amount.currency !== this.currency) {
      throw new Error("les devices sont différentes !");
    }

    return new Money(this.value + amount.value, this.currency);
  }

  public equals(other: Money) {
    return this.currency === other.currency && this.value === other.value;
  }
}

type Latitude = number;
type Longitude = number;

class Coordinate {
  constructor(public latitude: Latitude, public longitude: Longitude) {}
}

class ArticleId {
  public readonly value: string;

  constructor(value?: string) {
    this.value = value ?? uuid();
  }
}

// function addArticleToCart(article: ArticleId, cart: CartId) {

// }

class CategoryId {}

class Category {
  private id!: CategoryId;
}

class CartId {}

class Cart {
  private id: CartId;
  private items: CartItem[];

  constructor() {
    this.id = new CartId();
    this.items = [];
  }

  public addArticle(article: ArticleId) {
    if (this.items.length === 3) {
      throw new Error("le maximum d'articles est déjà atteint");
    }

    this.items.push(new CartItem(article));
  }
}

class CartItem {
  public readonly addedDate: Date;

  constructor(public readonly article: ArticleId) {
    this.addedDate = new Date();
  }
}

interface ArticleRepository {
  save(article: Article): void;
  getById(id: ArticleId): Article;
}

class SqliteArticleRepository implements ArticleRepository {
  getById(id: ArticleId): Article {
    // SELECT id, price, currency FROM articles;
    const snapshot = {
      id: "un id",
      price: 12,
      currency: "€",
    };
    return Article.__fromSnapshot(snapshot);
  }

  save(article: Article): void {
    // INSERT INTO articles (id, price, currency) VALUES(?,?,?)
    const { id, price, currency } = article.__takeSnapshot();
  }
}

type ArticleSnapshot = {
  id: string;
  price: number;
  currency: string;
};

class Article {
  private id: ArticleId;
  private category!: CategoryId;
  private ref: string;
  private price: Money;

  __takeSnapshot(): ArticleSnapshot {
    return {
      id: this.id.value,
      price: this.price.value,
      currency: this.price.currency,
    };
  }

  static __fromSnapshot(snap: ArticleSnapshot): Article {
    const art = new Article("", new Money(snap.price, snap.currency));
    art.id = new ArticleId(snap.id);

    return art;
  }

  // private status: "OPEN" | "CLOSE" = "OPEN";
  // private closedDate?: Date;

  // public close() {
  //   this.status = "CLOSE";
  //   this.closedDate = new Date();
  // }

  constructor(ref: string, price: Money) {
    this.id = new ArticleId();
    this.ref = ref;
    this.price = price;
  }

  public updatePrice(newPrice: Money) {
    this.price = newPrice;

    //this.storeEvent(new ArticlePriceUpdated(this.id, newPrice))
  }

  public addAmountToPrice(amount: Money) {
    this.price = this.price.add(amount);
  }

  public equals(article: Article) {
    return this.id === article.id;
  }
}

// new Article("ref1", -1);
// const article = new Article("ref1", 1);

// article.updatePrice(123);
