package com.matchandtrade.rest.v1.linkassembler;

import com.matchandtrade.persistence.common.Pagination;
import com.matchandtrade.persistence.common.SearchResult;
import com.matchandtrade.persistence.entity.AttachmentEntity;
import com.matchandtrade.persistence.entity.EssenceEntity;
import com.matchandtrade.rest.service.AttachmentService;
import com.matchandtrade.rest.v1.json.AttachmentJson;
import com.matchandtrade.rest.v1.transformer.AttachmentTransformer;
import com.matchandtrade.test.DefaultTestingConfiguration;
import com.matchandtrade.test.helper.AttachmentHelper;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;
import java.util.Map;

import static java.util.Collections.singletonList;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;

@RunWith(SpringRunner.class)
@DefaultTestingConfiguration
public class AttachmentLinkAssemblerIT {

	private AttachmentJson attachment;
	@Autowired
	private AttachmentHelper attachmentHelper;
	private AttachmentTransformer attachmentTransformer = new AttachmentTransformer();
	private AttachmentEntity existingAttachment;
	@Autowired
	private AttachmentLinkAssembler fixture;

	// TODO: MockBeans dirties the context. Can we create a mock factory for better performance?
	@MockBean(name = "mockedAttachmentService")
	private AttachmentService mockedAttachmentService;

	@Before
	public void before() {
		MockitoAnnotations.initMocks(this);

		existingAttachment = attachmentHelper.createPersistedEntity();
		attachment = attachmentTransformer.transform(existingAttachment);

		when(mockedAttachmentService.findByAttachmentId(attachment.getAttachmentId())).thenReturn(existingAttachment);
		fixture.attachmentService = mockedAttachmentService;
	}

	@Test
	public void assemble_When_HasAttachmentId_Then_AssembleLinks() {
		fixture.assemble(attachment);
		verifyLinks();
	}

	@Test
	public void assemble_When_SearchResultContainsJsonWithAttachmentId_Then_AssembleLinks() {
		SearchResult<AttachmentJson> searchResult = new SearchResult<>(singletonList(attachment), new Pagination());
		fixture.assemble(searchResult);
		verifyLinks();
	}

	private String buildSelfUrl(AttachmentJson attachment) {
		return "http://localhost/matchandtrade-api/v1/attachments/" + attachment.getAttachmentId();
	}

	private Map.Entry<String, String> obtainLink(String self, List<Map.Entry<String, String>> links) {
		return links.stream().filter(link -> self.equals(link.getKey())).findFirst().get();
	}

	private EssenceEntity obtainEssence(EssenceEntity.Type type, AttachmentEntity existingAttachment) {
		return existingAttachment.getEssences().stream().filter(e -> type.equals(e.getType())).findFirst().get();
	}

	private String obtainEssenceHref(EssenceEntity expectedOriginalEssence) {
		return "http://localhost/matchandtrade-api/essences/" + expectedOriginalEssence.getRelativePath();
	}

	private void verifyLinks() {
		Map.Entry<String, String> actualSelfLink = obtainLink("self", attachment.getLinks());
		assertEquals(buildSelfUrl(attachment), actualSelfLink.getValue());
		Map.Entry<String, String> actualOriginalLink = obtainLink("original", attachment.getLinks());
		EssenceEntity expectedOriginalEssence = obtainEssence(EssenceEntity.Type.ORIGINAL, existingAttachment);
		assertEquals(obtainEssenceHref(expectedOriginalEssence), actualOriginalLink.getValue());
		Map.Entry<String, String> actualThumbnailLink = obtainLink("thumbnail", attachment.getLinks());
		EssenceEntity expectedThumbnailEssence = obtainEssence(EssenceEntity.Type.THUMBNAIL, existingAttachment);
		assertEquals(obtainEssenceHref(expectedThumbnailEssence), actualThumbnailLink.getValue());
	}
}

@@ -282,65 +282,8 @@
 ty;%0A
-import com.matchandtrade.rest.service.AttachmentService;%0A
 impo
@@ -599,47 +599,8 @@
 th;%0A
-import org.mockito.MockitoAnnotations;%0A
 impo
@@ -662,68 +662,8 @@
 ed;%0A
-import org.springframework.boot.test.mock.mockito.MockBean;%0A
 impo
@@ -865,48 +865,8 @@
 als;
-%0Aimport static org.mockito.Mockito.when;
 %0A%0A@R
@@ -965,45 +965,8 @@
 IT %7B
-%0A%0A%09private AttachmentJson attachment;
 %0A%09@A
@@ -1150,21 +1150,15 @@
 ment
-;%0A%09@Autowired
+Entity;
 %0A%09pr
@@ -1177,295 +1177,124 @@
 ment
-LinkAssembler fixture;%0A%0A%09// TODO: MockBeans dirties the context. Can we create a mock factory for better performance?%0A%09@MockBean(name = %22mockedAttachmentService%22)%0A%09private AttachmentService mockedAttachmentService;%0A%0A%09@Before%0A%09public void before() %7B%0A%09%09MockitoAnnotations.initMocks(this);%0A
+Json existingAttachmentJson;%0A%09@Autowired%0A%09private AttachmentLinkAssembler fixture;%0A%0A%09@Before%0A%09public void before() %7B
 %0A%09%09e
@@ -1302,32 +1302,38 @@
 istingAttachment
+Entity
  = attachmentHel
@@ -1363,17 +1363,25 @@
 ty();%0A%09%09
-a
+existingA
 ttachmen
@@ -1381,16 +1381,20 @@
 tachment
+Json
  = attac
@@ -1442,178 +1442,15 @@
 ment
-);%0A%0A%09%09when(mockedAttachmentService.findByAttachmentId(attachment.getAttachmentId())).thenReturn(existingAttachment);%0A%09%09fixture.attachmentService = mockedAttachmentService
+Entity)
 ;%0A%09%7D
@@ -1543,17 +1543,25 @@
 ssemble(
-a
+existingA
 ttachmen
@@ -1557,24 +1557,28 @@
 ngAttachment
+Json
 );%0A%09%09verifyL
@@ -1766,17 +1766,25 @@
 tonList(
-a
+existingA
 ttachmen
@@ -1784,16 +1784,20 @@
 tachment
+Json
 ), new P
@@ -2698,17 +2698,25 @@
 %22self%22, 
-a
+existingA
 ttachmen
@@ -2708,32 +2708,36 @@
 istingAttachment
+Json
 .getLinks());%0A%09%09
@@ -2762,17 +2762,25 @@
 SelfUrl(
-a
+existingA
 ttachmen
@@ -2780,16 +2780,20 @@
 tachment
+Json
 ), actua
@@ -2883,25 +2883,33 @@
 %22original%22, 
-a
+existingA
 ttachment.ge
@@ -2897,32 +2897,36 @@
 istingAttachment
+Json
 .getLinks());%0A%09%09
@@ -3018,32 +3018,38 @@
 istingAttachment
+Entity
 );%0A%09%09assertEqual
@@ -3200,17 +3200,25 @@
 bnail%22, 
-a
+existingA
 ttachmen
@@ -3214,24 +3214,28 @@
 ngAttachment
+Json
 .getLinks())
@@ -3341,16 +3341,22 @@
 tachment
+Entity
 );%0A%09%09ass

Refactor AttachmentLinkAssemblerIT