package eu.dnetlib.enabling.is.sn;

import static org.junit.Assert.*; // NOPMD
import static org.mockito.Mockito.*; // NOPMD

import java.util.ArrayList;
import java.util.List;

import javax.xml.ws.wsaddressing.W3CEndpointReference;
import javax.xml.ws.wsaddressing.W3CEndpointReferenceBuilder;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnit44Runner;

import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscription;
import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscriptionRegistry;
import eu.dnetlib.enabling.tools.OpaqueResource;

/**
 * Test the default notification detector implementation.
 *
 * @author marko
 *
 */
@RunWith(MockitoJUnit44Runner.class)
public class NotificationDetectorImplTest {

	/**
	 * some type.
	 */
	private static final String SOME_TYPE = "SomeType";

	/**
	 * some resource identifier.
	 */
	private static final String SOME_ID = "123";

	/**
	 * Check if a message has the correct content.
	 *
	 * @author marko
	 *
	 */
	private final class CheckMessage extends ArgumentMatcher<NotificationMessage> {

		/**
		 * prefix.
		 */
		private final transient String prefix;

		/**
		 * constructor.
		 *
		 * @param prefix topic prefix
		 */
		CheckMessage(final String prefix) {
			super();
			this.prefix = prefix;
		}

		/**
		 * {@inheritDoc}
		 * @see org.mockito.ArgumentMatcher#matches(java.lang.Object)
		 */
		@Override
		public boolean matches(final Object argument) {
			final NotificationMessage message = (NotificationMessage) argument;
			return message.getSubscriptionId() == subscription.getSubscriptionId() && message.getResourceId().equals("123")
					&& message.getTopic().equals(prefix + ".*.*");
		}
	}

	/**
	 * instance under test.
	 */
	private transient NotificationDetectorImpl detector;

	/**
	 * registry mock.
	 */
	@Mock
	private transient ResourceStateSubscriptionRegistry registry;

	/**
	 * sender mock.
	 */
	@Mock
	private transient NotificationSender sender;

	/**
	 * resource mock.
	 */
	@Mock
	private transient OpaqueResource resource;

	/**
	 * resource subscription.
	 */
	@Mock
	private transient ResourceStateSubscription subscription;

	/**
	 * mock subscriber.
	 */
	private transient W3CEndpointReference subscriber;

	/**
	 * common.
	 */
	@Before
	public void setUp() {
		detector = new NotificationDetectorImpl();
		final List<ResourceStateSubscriptionRegistry> registries = new ArrayList<ResourceStateSubscriptionRegistry>();
		registries.add(registry);
		detector.setRegistries(registries);

		detector.setSender(sender);

		final W3CEndpointReferenceBuilder builder = new W3CEndpointReferenceBuilder();
		builder.address("http://test.com/test/test");
		subscriber = builder.build();

		final List<ResourceStateSubscription> subscriptions = new ArrayList<ResourceStateSubscription>();
		subscriptions.add(subscription);
		when(registry.listMatchingSubscriptions(ResourceStateSubscription.PREFIX_CREATE, SOME_TYPE, SOME_ID)).thenReturn(subscriptions);
		when(registry.listMatchingSubscriptions(ResourceStateSubscription.PREFIX_DELETE, SOME_TYPE, SOME_ID)).thenReturn(subscriptions);
		when(registry.listMatchingSubscriptions(ResourceStateSubscription.PREFIX_UPDATE, SOME_TYPE, SOME_ID)).thenReturn(subscriptions);

		when(resource.getResourceId()).thenReturn(SOME_ID);
		when(resource.getResourceType()).thenReturn(SOME_TYPE);

		when(subscription.getSubscriptionId()).thenReturn("sn123");
		when(subscription.getSubscriber()).thenReturn(subscriber);
		when(subscription.getXpath()).thenReturn("");
		when(subscription.getType()).thenReturn("*");
		when(subscription.getResourceId()).thenReturn("*");
	}

	/**
	 * test 'create'.
	 */
	@Test
	public void testResourceCreated() {
		when(subscription.getPrefix()).thenReturn(ResourceStateSubscription.PREFIX_CREATE);

		detector.resourceCreated(resource);

		verify(sender).send(eq(subscriber), argThat(new CheckMessage(ResourceStateSubscription.PREFIX_CREATE)));

		assertNotNull("dummy", sender);
	}

	/**
	 * test 'delete'.
	 */
	@Test
	public void testResourceDeleted() {
		when(subscription.getPrefix()).thenReturn(ResourceStateSubscription.PREFIX_DELETE);

		detector.resourceDeleted(resource);

		verify(sender).send(eq(subscriber), argThat(new CheckMessage(ResourceStateSubscription.PREFIX_DELETE)));

		assertNotNull("dummy", sender);
	}

	/**
	 * test 'update'.
	 */
	@Test
	public void testResourceUpdated() {
		when(subscription.getXpath()).thenReturn(null);
		when(subscription.getPrefix()).thenReturn(ResourceStateSubscription.PREFIX_UPDATE);

		detector.resourceUpdated(resource, resource);

		verify(sender).send(eq(subscriber), argThat(new CheckMessage(ResourceStateSubscription.PREFIX_UPDATE)));

		assertNotNull("dummy", sender);

	}

}
