"""
Tests in the wider vicinity of cone search.
"""

#c Copyright 2008-2025, the GAVO project <gavo@ari.uni-heidelberg.de>
#c
#c This program is free software, covered by the GNU GPL.  See the
#c COPYING file in the source distribution.


from gavo.helpers import testhelpers

from gavo import api
from gavo.helpers import trialhelpers
from gavo.protocols import scs
from gavo.web import vodal

import tresc


class QueryBuildingTest(testhelpers.VerboseTest,
		metaclass=testhelpers.SamplesBasedAutoTest):
	def _runTest(self, sample):
		tdLit, expected = sample
		td = api.parseFromString(api.TableDef, tdLit)
		self.assertEqual(
			scs.getRadialCondition(td, 10, 13, 1),
			expected)
	
	samples = [
		("""<table id="t" onDisk="True">
				<mixin>//scs#q3cindex</mixin>
				<column name="raj2000" ucd="pos.eq.ra;meta.main"/>
				<column name="dej2000" ucd="pos.eq.dec;meta.main"/>
			</table>""",
			"q3c_radial_query(raj2000, dej2000, 10, 13, 1)"),
		("""<table id="t" onDisk="True">
				<column name="ra" ucd="pos.eq.ra;meta.main"/>
				<column name="dec" ucd="pos.eq.dec;meta.main"/>
			</table>""",
			"spoint(radians(ra), radians(dec))"
			"  <@ scircle(spoint(radians(10), radians(13)), radians(1))"),
		("""<table id="t" onDisk="True" mixin="//scs#pgs-pos-index">
				<column name="quoted/Right Ascension" ucd="pos.eq.ra;meta.main"/>
				<column name="dec" ucd="pos.eq.dec;meta.main"/>
			</table>""",
			'spoint(radians("Right Ascension"), radians(dec))'
			"  <@ scircle(spoint(radians(10), radians(13)), radians(1))"),
		("""<table id="t" onDisk="True">
				<column name="ssa_location" type="spoint" ucd="pos.eq"/>
			</table>""",
			"ssa_location <@ scircle(spoint(radians(10), radians(13)), radians(1))"),

	]
		

class AnomalousQueryBuildingTest(testhelpers.VerboseTest):
	tdPat = """<table id="t" onDisk="True">
				<column name="raj2000" ucd="pos.eq.ra;meta.main"/>
				<column name="dej2000" ucd="pos.eq.dec;meta.main"/>
				<column name="knatter"/>
			</table>"""

	def testInjection(self):
		td = api.parseFromString(api.TableDef, self.tdPat)
		self.assertRaisesWithMsg(api.ReportableError,
			"getRadialCondition's last resort alarm triggered.",
			scs.getRadialCondition,
			(td, "); drop table users", None, None))
	
	def testOverriding(self):
		td = api.parseFromString(api.TableDef, self.tdPat)
		self.assertEqual(
			scs.getRadialCondition(td,
				"%(RA)s", "%(DEC)s", "%(SR)s",
				decColName="knatter"),
			"spoint(radians(raj2000), radians(knatter))  <@"
			" scircle(spoint(radians(%(RA)s), radians(%(DEC)s)), radians(%(SR)s))")

	def testMissingUCD(self):
		td = api.parseFromString(api.TableDef,
			self.tdPat.replace("pos.eq.dec;", ""))
		self.assertRaisesWithMsg(api.StructureError,
			"No column for pos.eq.dec;meta.main",
			scs.getRadialCondition,
			(td, "%(RA)s", "%(DEC)s", "%(SR)s"))
	

class _ConecatTable(tresc.RDDataResource):
	rdName = "data/cores"
	dataId = "import_conecat"

CONECAT_TABLE = _ConecatTable()

class ConeSearchTest(testhelpers.VerboseTest):
	resources = [("cstable", CONECAT_TABLE),
		("fs", tresc.fakedSimbad)]

	def testRadiusAddedSCS(self):
		svc = api.resolveCrossId("data/cores#scs")
		res = trialhelpers.runSvcWith(svc, "scs.xml",
			{"RA": ["1"], "DEC": ["2"], "SR": ["3"]}
			).getPrimaryTable()
		self.assertAlmostEqual(res.rows[0]["_r"], 0.5589304685425)
		col = res.tableDef.getColumnByName("_r")
		self.assertEqual(col.unit, "deg")
		self.assertEqual(col.ucd, "pos.angDistance")

	def testRadiusAddedForm(self):
		svc = api.resolveCrossId("data/cores#scs")
		res = trialhelpers.runSvcWith(svc, "form",
			{"hscs_pos": "1, 2", "hscs_sr": str(3*60)}
			).getPrimaryTable()
		self.assertAlmostEqual(res.rows[0]["_r"], 0.5589304685425)

	def testRadiusAddedFormObjectres(self):
		svc = api.resolveCrossId("data/cores#scs")
		res = trialhelpers.runSvcWith(svc, "form",
			{"hscs_pos": "Aldebaran", "hscs_sr": str(180*60)}
			).getPrimaryTable()
		self.assertAlmostEqual(res.rows[0]["_r"], 67.9075866114036)

	def testNoRadiusWithoutPos(self):
		svc = api.resolveCrossId("data/cores#scs")
		res = trialhelpers.runSvcWith(svc, "form", {"id": "0"}
			).getPrimaryTable()
		self.assertTrue(res.rows[0]["_r"] is None)


class _RenderedSCSResponse(testhelpers.TestResource):
	resources = [("conetable", CONECAT_TABLE)]
	def make(self, deps):
		request = trialhelpers.FakeRequest("anything?goes=here",
			args={"RA": ["1"], "DEC": ["2"], "SR": ["3"]})
		pg = vodal.SCSRenderer(request, api.resolveCrossId("data/cores#scs"))
		return testhelpers.getXMLTree(pg.renderSync(request), debug=False)


class DataOriginTest(testhelpers.VerboseTest):
	resources = [("tree", _RenderedSCSResponse())]

	def _getINFO(self, key):
		matches = self.tree.xpath(f"//INFO[@name='{key}']")
		assert len(matches)==1
		return matches[0].get("value")

	def _getINFOs(self, key):
		return set(m.get("value")
			for m in self.tree.xpath(f"//INFO[@name='{key}']"))

	# Keep the sequence of tests in sync with the sequence of items in
	# the data origin paper so it's easy to see whether we're covering
	# them all.

	def testIVOID(self):
		self.assertEqual(self._getINFOs("ivoid"), {
			'ivo://x-testing/data/cores/singlearg',
			'ivo://x-testing/data/cores/scs',
			'ivo://x-testing/data/cores/pc',
			'ivo://x-testing/data/cores/cstest',
			'ivo://x-testing/data/cores/dl'})

	def testPublisher(self):
		self.assertEqual(
			self._getINFO("publisher"),
			"Your organisation's name")

	def testServerSoftware(self):
		self.assertEqual(self._getINFO("server_software"),
			api.SERVER_SOFTWARE)

	def testRequest(self):
		self.assertEqual(self._getINFO("request"),
			"http://localhost:8080/anything%3Fgoes%3Dhere?RA=1&DEC=2&SR=3")

	def testRequestDate(self):
		self.assertTrue(self._getINFO("request_date").startswith("20"))

	def testContact(self):
		self.assertEqual(
			self._getINFO("contact"),
			"invalid@wherever.else")

	def testReferenceURL(self):
		self.assertEqual(
			self._getINFOs("reference_url"),
			set(["http://localhost:8080/tableinfo/test.conecat",
				'http://localhost:8080/data/cores/scs/info']))

	def testSource(self):
		# not given in source, make sure it doesn't fantasise something
		self.assertEqual(
			len(self.tree.xpath("//INFO[@name='publication_id']")),
			0)

	def testResourceVersion(self):
		self.assertEqual(
			self._getINFO("resource_version"),
			"2.3.1pl2+git_deadbeef")

	maxDiff = None
	def testRights(self):
		self.assertEqual(
			self._getINFO("rights").strip(),
			'To the extent possible under law, the publisher has waived all copyright and related or neighboring rights to nothing in particular.  For details, see the `Creative Commons CC0 1.0 Public Domain dedication <http://creativecommons.org/publicdomain/zero/1.0/>`_.  Of course, you should still give proper credit when using this data as required by good scientific practice.  .. image:: /static/img/cc0.png    :alt: [CC0]')

	def testRightsURI(self):
		self.assertEqual(
			self._getINFO("rights_uri"),
			"https://spdx.org/licenses/CC0-1.0.html")

	def testCreator(self):
		self.assertEqual(
			self._getINFOs("creator"),
			set([
				'Gandalf, W.',
				'Baggins, B.',
				'Baggins, F.',]))


if __name__=="__main__":
	testhelpers.main(QueryBuildingTest)
