// Path: shopping-context/src/main/java/se/citerus/cqrs/bookstore/shopping/api/AddItemRequest.java
// public class AddItemRequest extends TransportObject {
// 
//   @NotEmpty
//   @Pattern(regexp = ID_PATTERN)
//   public String productId;
// 
// }
// 
// Path: shopping-context/src/main/java/se/citerus/cqrs/bookstore/shopping/api/CartDto.java
// public class CartDto extends TransportObject {
// 
//   public String cartId;
// 
//   public long totalPrice;
// 
//   public int totalQuantity;
// 
//   public List<LineItemDto> lineItems;
// 
// }
// 
// Path: shopping-context/src/main/java/se/citerus/cqrs/bookstore/shopping/api/CreateCartRequest.java
// public class CreateCartRequest extends TransportObject {
// 
//   @NotEmpty
//   @Pattern(regexp = ID_PATTERN)
//   public String cartId;
// 
// }
// 
// Path: shopping-context/src/main/java/se/citerus/cqrs/bookstore/shopping/api/LineItemDto.java
// public class LineItemDto extends TransportObject {
// 
//   public String productId;
// 
//   public String title;
// 
//   public long price;
// 
//   public int quantity;
// 
//   public long totalPrice;
// 
// }
// 
// Path: shopping-context/src/main/java/se/citerus/cqrs/bookstore/shopping/client/productcatalog/BookDto.java
// @JsonIgnoreProperties(ignoreUnknown = true)
// public class BookDto extends TransportObject {
// 
//   public String title;
// 
//   public String isbn;
// 
// }
// 
// Path: shopping-context/src/main/java/se/citerus/cqrs/bookstore/shopping/client/productcatalog/ProductCatalogClient.java
// public class ProductCatalogClient {
// 
//   private final Client client;
//   private final String serviceUrl;
// 
//   private ProductCatalogClient(Client client, String serviceUrl) {
//     this.client = client;
//     this.serviceUrl = serviceUrl;
//   }
// 
//   public static ProductCatalogClient create(Client client, String serviceUrl) {
//     return new ProductCatalogClient(client, serviceUrl);
//   }
// 
//   public ProductDto getProduct(String productId) {
//     return client.target(serviceUrl + productId).request().get(ProductDto.class);
//   }
// 
// }
// 
// Path: shopping-context/src/main/java/se/citerus/cqrs/bookstore/shopping/client/productcatalog/ProductDto.java
// @JsonIgnoreProperties(ignoreUnknown = true)
// public class ProductDto extends TransportObject {
// 
//   public BookDto book;
// 
//   public long price;
// 
// }
// 
// Path: shopping-context/src/main/java/se/citerus/cqrs/bookstore/shopping/infrastructure/InMemoryCartRepository.java
// public class InMemoryCartRepository implements CartRepository {
// 
//   private ConcurrentHashMap<String, Cart> sessions = new ConcurrentHashMap<>();
// 
//   public void save(Cart cart) {
//     if (sessions.putIfAbsent(cart.cartId, cart) != null) {
//       throw new IllegalArgumentException(format("Shopping cart with id '%s' already exists", cart.cartId));
//     }
//   }
// 
//   public Cart get(String cartId) {
//     Cart cart = sessions.get(cartId);
//     checkArgument(cart != null, "No shopping cart with id '%s' exists", cartId);
//     return cart;
//   }
// 
//   public Cart find(String cartId) {
//     return sessions.get(cartId);
//   }
// 
//   public void delete(String cartId) {
//     sessions.remove(cartId);
//   }
// 
// }


import io.dropwizard.testing.junit.ResourceTestRule;
import org.junit.After;
import org.junit.ClassRule;
import org.junit.Test;
import se.citerus.cqrs.bookstore.shopping.api.AddItemRequest;
import se.citerus.cqrs.bookstore.shopping.api.CartDto;
import se.citerus.cqrs.bookstore.shopping.api.CreateCartRequest;
import se.citerus.cqrs.bookstore.shopping.api.LineItemDto;
import se.citerus.cqrs.bookstore.shopping.client.productcatalog.BookDto;
import se.citerus.cqrs.bookstore.shopping.client.productcatalog.ProductCatalogClient;
import se.citerus.cqrs.bookstore.shopping.client.productcatalog.ProductDto;
import se.citerus.cqrs.bookstore.shopping.infrastructure.InMemoryCartRepository;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import java.util.UUID;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
import static javax.ws.rs.core.Response.Status.NOT_FOUND;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.*;

    ProductDto productDto = new ProductDto();
    productDto.price = price;
    productDto.book = new BookDto();
    productDto.book.title = title;
    when(productCatalogClient.getProduct(productId)).thenReturn(productDto);
    CartDto cart = addItemToCart(cartId, addProductItemRequest(productId)).readEntity(CartDto.class);

    LineItemDto expectedLineItem = new LineItemDto();
    expectedLineItem.productId = productId;
    expectedLineItem.title = title;
    expectedLineItem.price = price;
    expectedLineItem.quantity = 1;
    expectedLineItem.totalPrice = price;

    assertThat(cart.lineItems, hasSize(1));
    assertThat(cart.lineItems, hasItems(expectedLineItem));
  }

  @Test
  public void cannotAddNonExistingItem() {
    String cartId = UUID.randomUUID().toString();
    createCartWithId(cartId);

    AddItemRequest addItemRequest = addProductItemRequest(UUID.randomUUID().toString());
    Response response = addItemToCart(cartId, addItemRequest);

    assertThat(response.getStatusInfo().getStatusCode(), is(BAD_REQUEST.getStatusCode()));
  }

// Path: shopping-context/src/main/java/se/citerus/cqrs/bookstore/shopping/api/AddItemRequest.java
// public class AddItemRequest extends TransportObject {
// 
//   @NotEmpty
//   @Pattern(regexp = ID_PATTERN)
//   public String productId;
// 
// }
// 
// Path: shopping-context/src/main/java/se/citerus/cqrs/bookstore/shopping/api/CartDto.java
// public class CartDto extends TransportObject {
// 
//   public String cartId;
// 
//   public long totalPrice;
// 
//   public int totalQuantity;
// 
//   public List<LineItemDto> lineItems;
// 
// }
// 
// Path: shopping-context/src/main/java/se/citerus/cqrs/bookstore/shopping/api/CreateCartRequest.java
// public class CreateCartRequest extends TransportObject {
// 
//   @NotEmpty
//   @Pattern(regexp = ID_PATTERN)
//   public String cartId;
// 
// }
// 
// Path: shopping-context/src/main/java/se/citerus/cqrs/bookstore/shopping/api/LineItemDto.java
// public class LineItemDto extends TransportObject {
// 
//   public String productId;
// 
//   public String title;
// 
//   public long price;
// 
//   public int quantity;
// 
//   public long totalPrice;
// 
// }
// 
// Path: shopping-context/src/main/java/se/citerus/cqrs/bookstore/shopping/client/productcatalog/BookDto.java
// @JsonIgnoreProperties(ignoreUnknown = true)
// public class BookDto extends TransportObject {
// 
//   public String title;
// 
//   public String isbn;
// 
// }
// 
// Path: shopping-context/src/main/java/se/citerus/cqrs/bookstore/shopping/client/productcatalog/ProductCatalogClient.java
// public class ProductCatalogClient {
// 
//   private final Client client;
//   private final String serviceUrl;
// 
//   private ProductCatalogClient(Client client, String serviceUrl) {
//     this.client = client;
//     this.serviceUrl = serviceUrl;
//   }
// 
//   public static ProductCatalogClient create(Client client, String serviceUrl) {
//     return new ProductCatalogClient(client, serviceUrl);
//   }
// 
//   public ProductDto getProduct(String productId) {
//     return client.target(serviceUrl + productId).request().get(ProductDto.class);
//   }
// 
// }
// 
// Path: shopping-context/src/main/java/se/citerus/cqrs/bookstore/shopping/client/productcatalog/ProductDto.java
// @JsonIgnoreProperties(ignoreUnknown = true)
// public class ProductDto extends TransportObject {
// 
//   public BookDto book;
// 
//   public long price;
// 
// }
// 
// Path: shopping-context/src/main/java/se/citerus/cqrs/bookstore/shopping/infrastructure/InMemoryCartRepository.java
// public class InMemoryCartRepository implements CartRepository {
// 
//   private ConcurrentHashMap<String, Cart> sessions = new ConcurrentHashMap<>();
// 
//   public void save(Cart cart) {
//     if (sessions.putIfAbsent(cart.cartId, cart) != null) {
//       throw new IllegalArgumentException(format("Shopping cart with id '%s' already exists", cart.cartId));
//     }
//   }
// 
//   public Cart get(String cartId) {
//     Cart cart = sessions.get(cartId);
//     checkArgument(cart != null, "No shopping cart with id '%s' exists", cartId);
//     return cart;
//   }
// 
//   public Cart find(String cartId) {
//     return sessions.get(cartId);
//   }
// 
//   public void delete(String cartId) {
//     sessions.remove(cartId);
//   }
// 
// }


// Path: shopping-context/src/test/java/se/citerus/cqrs/bookstore/shopping/resource/CartResourceTest.java
import io.dropwizard.testing.junit.ResourceTestRule;
import org.junit.After;
import org.junit.ClassRule;
import org.junit.Test;
import se.citerus.cqrs.bookstore.shopping.api.AddItemRequest;
import se.citerus.cqrs.bookstore.shopping.api.CartDto;
import se.citerus.cqrs.bookstore.shopping.api.CreateCartRequest;
import se.citerus.cqrs.bookstore.shopping.api.LineItemDto;
import se.citerus.cqrs.bookstore.shopping.client.productcatalog.BookDto;
import se.citerus.cqrs.bookstore.shopping.client.productcatalog.ProductCatalogClient;
import se.citerus.cqrs.bookstore.shopping.client.productcatalog.ProductDto;
import se.citerus.cqrs.bookstore.shopping.infrastructure.InMemoryCartRepository;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import java.util.UUID;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
import static javax.ws.rs.core.Response.Status.NOT_FOUND;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.*;


    ProductDto productDto = new ProductDto();
    productDto.price = price;
    productDto.book = new BookDto();
    productDto.book.title = title;
    when(productCatalogClient.getProduct(productId)).thenReturn(productDto);
    CartDto cart = addItemToCart(cartId, addProductItemRequest(productId)).readEntity(CartDto.class);

    LineItemDto expectedLineItem = new LineItemDto();
    expectedLineItem.productId = productId;
    expectedLineItem.title = title;
    expectedLineItem.price = price;
    expectedLineItem.quantity = 1;
    expectedLineItem.totalPrice = price;

    assertThat(cart.lineItems, hasSize(1));
    assertThat(cart.lineItems, hasItems(expectedLineItem));
  }

  @Test
  public void cannotAddNonExistingItem() {
    String cartId = UUID.randomUUID().toString();
    createCartWithId(cartId);

    AddItemRequest addItemRequest = addProductItemRequest(UUID.randomUUID().toString());
    Response response = addItemToCart(cartId, addItemRequest);

    assertThat(response.getStatusInfo().getStatusCode(), is(BAD_REQUEST.getStatusCode()));
  }

  private AddItemRequest addProductItemRequest(String productId) {