package eu.dnetlib.actionmanager.actions;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Resource;
import javax.xml.transform.TransformerException;

import eu.dnetlib.actionmanager.common.Agent;
import eu.dnetlib.actionmanager.common.Agent.AGENT_TYPE;
import eu.dnetlib.actionmanager.common.Operation;
import eu.dnetlib.actionmanager.common.Provenance;
import eu.dnetlib.actionmanager.rmi.ActionManagerException;
import eu.dnetlib.data.proto.OafProtos.Oaf;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.DocumentException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import static org.junit.Assert.*;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/eu/dnetlib/actionmanager/actions/applicationContext-actionmanager-test.xml" })
public class ActionFactoryTest {

	private static final Log log = LogFactory.getLog(ActionFactoryTest.class);
	private final static Agent agent = new Agent("agentId", "agentName", AGENT_TYPE.algo);
	private final static String trust = "0.9";
	private final InputStream recordDataciteInputStream = getClass().getResourceAsStream("recordDatacite.xml");
	private final InputStream recordDatacite2InputStream = getClass().getResourceAsStream("recordDatacite2.xml");
	private final InputStream recordOafInputStream = getClass().getResourceAsStream("record.xml");
	@Resource
	private ActionFactory actionFactory;

	// @Before
	// public void setUp() throws Exception {
	//
	// }

	@Test
	public void testBeans() {
		assertNotNull(actionFactory);
		assertNotNull(actionFactory.getXslts());
		assertFalse(actionFactory.getXslts().isEmpty());
	}

	@Test
	public void testDataciteInsert() throws ActionManagerException, IOException, TransformerException, DocumentException {

		XsltInfoPackageAction action =
				actionFactory.generateInfoPackageAction("datacite2insertActions", "rawSet", agent, Operation.INSERT, asString(recordDataciteInputStream),
						Provenance.sysimport_crosswalk_datasetarchive, trust);

		checkActions(action, action.asAtomicActions());
	}

	@Test
	public void testDatacite2Insert() throws ActionManagerException, IOException, TransformerException, DocumentException {

		XsltInfoPackageAction action =
				actionFactory.generateInfoPackageAction("datacite2insertActions", "rawSet", agent, Operation.INSERT, asString(recordDatacite2InputStream),
						Provenance.sysimport_crosswalk_datasetarchive, trust);

		checkActions(action, action.asAtomicActions());
	}

	@Test
	public void testRecordOafInsert() throws ActionManagerException, IOException, TransformerException, DocumentException {

		XsltInfoPackageAction action =
				actionFactory.generateInfoPackageAction("dmf2insertActions", "rawSet", agent, Operation.INSERT, asString(recordOafInputStream),
						Provenance.sysimport_crosswalk_datasetarchive, trust);

		checkActions(action, action.asAtomicActions());
	}

	@Test
	public void testRecordOafUpdate() throws ActionManagerException, IOException, TransformerException, DocumentException {

		XsltInfoPackageAction action =
				actionFactory.generateInfoPackageAction("dmf2updateActions", "rawSet", agent, Operation.INSERT, asString(recordOafInputStream),
						Provenance.sysimport_crosswalk_datasetarchive, trust);
		checkActions(action, action.asAtomicActions());
	}

	private void checkActions(final XsltInfoPackageAction action, final List<AtomicAction> actions)
			throws TransformerException, DocumentException, com.google.protobuf.InvalidProtocolBufferException {
		for (AtomicAction a : action.calculateAtomicActions()) {
			assertNotNull(a.getTargetValue());

			String actionJSON = a.toString();

			log.info(actionJSON);

			final AtomicAction aa = AtomicAction.fromJSON(actionJSON);

			assertEquals(a.getRawSet(), aa.getRawSet());
			assertEquals(a.getTargetColumn(), aa.getTargetColumn());
			assertEquals(a.getTargetColumnFamily(), aa.getTargetColumnFamily());
			assertEquals(a.getTargetRowKey(), aa.getTargetRowKey());
			assertEquals(a.getActionType(), aa.getActionType());
			assertEquals(a.getRowKey(), aa.getRowKey());

			assertEquals(a.getAgent().getId(), aa.getAgent().getId());
			assertEquals(a.getAgent().getName(), aa.getAgent().getName());
			assertEquals(a.getAgent().getType(), aa.getAgent().getType());

			assertTrue(Arrays.equals(a.getTargetValue(), aa.getTargetValue()));

			System.out.println(Oaf.parseFrom(aa.getTargetValue()));
		}

		for (AtomicAction a : actions) {
			assertNotNull(a);
		}
		log.info("N. puts: " + actions.size());
	}

	private String asString(final InputStream i) throws IOException {
		StringWriter writer = new StringWriter();
		IOUtils.copy(i, writer);
		return writer.toString();
	}
}
