"""
Ask a RegTAP registry if any updates have happened to one of our records.

If so, update and re-submit the corresponding entries.

This script is usually run from an exec in voidoi, but it can safely
be run manually, too.
"""

import datetime
import io

from lxml import etree

from gavo import api
from gavo import votable
from gavo.votable import V

import registration
registration.RD = api.getRD("voidoi/q")
registration.initModule()


REGISTRY_ENDPOINT = "http://reg.g-vo.org/tap"


def iterUpdatedIVOIDs():
	"""iterates over IVOIDs of services we should be updating because
	their RRs have been updated upstream.
	"""
	# first, pull what's our last state
	with api.getTableConn() as conn:
		ivoidVsDate = conn.query("SELECT ivoid, date_reg FROM voidoi.dois"
							" WHERE doi IS NOT NULL")
		toUpload = V.VOTABLE[
			V.RESOURCE[
				votable.DelayedTable(
					V.TABLE[
						V.FIELD(name="ivoid", datatype="char", arraysize="*"),
						V.FIELD(name="date_reg", datatype="char", arraysize="*",
							xtype="adql:TIMESTAMP"),],
					ivoidVsDate,
					V.BINARY2)]]
		toUploadFile = io.BytesIO()
		votable.write(toUpload, toUploadFile)

	# then, compare it with what's in the registry
	toUploadFile.seek(0)
	job = votable.ADQLTAPJob(REGISTRY_ENDPOINT,
		"SELECT ivoid FROM"
		" rr.resource"
		" JOIN tap_upload.t USING (ivoid)"
		" WHERE date_reg<updated")
	try:
		job.addUpload("t", toUploadFile)
		job.run()
		data, metadata = votable.load(job.openResult())
		for row in metadata.iterDicts(data):
			yield row["ivoid"]
	finally:
		job.delete()


def updateForIVOID(ivoid):
	"""updates local and remote metadata for ivoid.
	"""
	fullRecord = registration.getRegistryRecord(ivoid)
	dateReg = datetime.datetime.utcnow()
	with api.getWritableAdminConn() as conn:
		conn.execute("UPDATE voidoi.dois SET"
			" full_record=%(fullRecord)s,"
			" date_reg=%(dateReg)s"
			" WHERE ivoid=%(ivoid)s",
			locals())
		doi = next(conn.queryToDicts("SELECT doi FROM voidoi.dois"
			" WHERE ivoid=%(ivoid)s", locals()))["doi"]

		recId, dcTree = registration.DATACITE_INTERFACE.translate(
			etree.fromstring(fullRecord), lambda rec_id: rec_id==ivoid and doi)
		if registration.DATACITE_INTERFACE.datacite_endpoint:
			registration.DATACITE_INTERFACE.upload(
				dcTree,
				registration.makeLandingPageURL(doi))


def parseCommandLine():
	import argparse
	parser = argparse.ArgumentParser(
		prog="update_records",
		description="Update voidoi VOResource")
	parser.add_argument("ivoid", nargs="*", type=str,
		help="ivoids to manually re-harvest; default is to"
			" obtain updated records.")
	return parser.parse_args()


def main():
	api.LoggingUI(api.ui)

	args = parseCommandLine()

	if args.ivoid:
		toProcess = args.ivoid
	else:
		toProcess = iterUpdatedIVOIDs()

	for ivoid in toProcess:
		try:
			updateForIVOID(ivoid)
			print("Updated DOI metadata for %s successfully"%ivoid)
		except Exception as ex:
			import traceback; traceback.print_exc()
			api.ui.notifyWarning("DOI metadata for ivoid %s should be updated,"
				" but update failed (%s)"%(ivoid, ex))


if __name__=="__main__":
	main()
