package eu.dnetlib.openaire.funders;

import java.io.StringReader;
import java.util.stream.Collectors;

import eu.dnetlib.openaire.exporter.model.funders.ExtendedFunderDetails;
import eu.dnetlib.openaire.exporter.model.funders.FunderDetails;
import eu.dnetlib.openaire.exporter.model.funders.FundingStream;
import eu.dnetlib.openaire.funders.domain.db.FunderDbEntry;
import eu.dnetlib.openaire.funders.domain.db.FundingPathDbEntry;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;

import static org.apache.commons.lang3.StringUtils.*;

public class ConversionUtils {

	public static final String SEPARATOR = "::";

	public static FunderDetails asFunderDetails(final FunderDbEntry fdb) {
		final FunderDetails f = new FunderDetails();

		f.setId(fdb.getId());
		f.setName(fdb.getName());
		f.setShortname(fdb.getShortname());
		f.setJurisdiction(fdb.getJurisdiction());
		f.setRegistrationDate(fdb.getRegistrationdate());
		f.setLastUpdateDate(fdb.getLastupdatedate());

		return f;
	}

	public static ExtendedFunderDetails asExtendedFunderDetails(final FunderDbEntry fdb) {
		final ExtendedFunderDetails f = new ExtendedFunderDetails(asFunderDetails(fdb));

		if (fdb.getFundingpaths() != null) {
			f.setFundingStreams(
					fdb.getFundingpaths().stream()
						.map(ConversionUtils::asFundingStream)
						.collect(Collectors.toList()));
		}

		return f;
	}

	private static FundingStream asFundingStream(final FundingPathDbEntry pathDbEntry) {
		final FundingStream f = new FundingStream();

		try {
			final Document xml = new SAXReader().read(new StringReader(pathDbEntry.getPath()));

			for(int i=2;i>=0;i--) {
				if (hasFundingLevel(i, xml)) {
					f.setId(getId(i, xml));
					f.setName(getName(i, xml));
					break;
				}
			}

			if (isBlank(f.getId()) && isNoneBlank(xml.valueOf("//funder/id/text()"))) {
				f.setId(xml.valueOf("//funder/shortname/text()"));
				f.setName(xml.valueOf("//funder/name/text()"));
			}

			if (isBlank(f.getId())) {
				throw new IllegalStateException("invalid funding path:\n" + xml.asXML());
			}

			return f;

		} catch (DocumentException e) {
			throw new IllegalStateException("unable to parse funding path:\n" + pathDbEntry.getPath());
		}
	}

	private static String getName(int level, final Document d) {
		return d.valueOf(String.format("//funding_level_%s/description/text()", level));
	}

	private static String getId(int level, final Document d) {
		return substringAfter(
				d.valueOf(
					String.format("//funding_level_%s/id/text()", level)
				), SEPARATOR);
	}

	private static boolean hasFundingLevel(int level, Document d) {
		return isNotBlank(getId(level, d));
	}
}
