package org.zheng.demo.repository;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.List;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.transaction.annotation.Transactional;
import org.zheng.demo.entity.Order;
import org.zheng.demo.entity.OrderItemId;
import org.zheng.demo.entity.OrderLineItem;
import org.zheng.demo.entity.Product;
import org.zheng.demo.entity.ProductProfile;

@DataJpaTest
@Transactional
class OrderRepoTest {

	@Autowired
	private OrderLineItemRepo lineItemRepo;

	@Autowired
	private OrderRepo orderRep;

	@Autowired
	private ProductProfileRepo prodProfRepo;

	@Autowired
	private ProductRepo prodRepo;

	private Product prod1;
	private Product prod2;

	@BeforeEach
	void setup() {
		prod1 = saveProduct("product 1", "some details");
		prod2 = saveProduct("product 2", "some details");
	}

	private Order buildOrder(final String orderName) {
		Order order = new Order();
		order.setName(orderName);
		return order;
	}

	private OrderLineItem buildOrderItem(final Order order, final Product prod, final Integer itemQuantity) {
		OrderLineItem item = new OrderLineItem();

		OrderItemId itemId1 = new OrderItemId();
		itemId1.setOrderId(order.getId());

		itemId1.setProductId(prod.getId());

		item.setId(itemId1);
		item.setOrder(order);
		item.setProduct(prod);
		return item;
	}

	@Test
	void test_save_order() {
		// create an order
		Order order = buildOrder("first order");
		assertNull(order.getId());
		orderRep.save(order);
		assertNotNull(order.getId());

		// create an order line item
		OrderLineItem item1 = buildOrderItem(order, prod1, 1);
		lineItemRepo.save(item1);

		OrderLineItem item2 = buildOrderItem(order, prod2, 2);
		lineItemRepo.save(item2);

		List<OrderLineItem> items = lineItemRepo.findAll();
		assertEquals(2, items.size());
	}

	@Test
	void test_save_order_update() {
		// create an order
		Order order = buildOrder("first order");
		orderRep.save(order);

		// create an order line item
		OrderLineItem item1 = buildOrderItem(order, prod1, 1);
		lineItemRepo.save(item1);

		item1.setQuantity(2);

		lineItemRepo.save(item1);

		List<OrderLineItem> items = lineItemRepo.findAll();
		assertEquals(1, items.size());
	}

	@Test
	void test_save_item_wo_prod_throw_error() {
		// create an order
		Order order = buildOrder("first order");
		orderRep.save(order);

		// create an order line item
		OrderLineItem item1 = buildOrderItem(order, prod1, 1);
		item1.setProduct(null);
		JpaSystemException jpaException = assertThrows(JpaSystemException.class, () -> lineItemRepo.save(item1));
		assertTrue(jpaException.getMessage().contains(
				"attempted to assign id from null one-to-one property [org.zheng.demo.entity.OrderLineItem.product"));

	}

	private Product saveProduct(final String productName, final String prodDetail) {
		Product prod = new Product();
		prod.setName(productName);

		prod = prodRepo.save(prod);

		ProductProfile prodProfile = new ProductProfile();
		prodProfile.setProduct(prod);
		prodProfile.setProductDetail(prodDetail);

		prodProfRepo.save(prodProfile);

		return prod;
	}

}
