import importlib.util
import json
import subprocess
import unittest
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
spec = importlib.util.spec_from_file_location('catalog_codec', ROOT / 'protocol/catalog_v2.py')
codec = importlib.util.module_from_spec(spec)
spec.loader.exec_module(codec)


class ContractTests(unittest.TestCase):
    def fixtures(self, revision):
        directory = ROOT / 'fixtures' / f'revision-{revision}'
        header = json.loads((directory / 'header.json').read_text())['header']
        chunks = [json.loads(p.read_text())['chunk'] for p in sorted(directory.glob('chunk-*.json'))]
        return header, chunks

    def test_unknown_measurements(self):
        header, chunks = self.fixtures(1)
        data = codec.reconstruct(header, chunks)
        self.assertIn('custom.sensors.vendorNew.temperature', [r.get('path') for r in data])

    def test_800_records_and_reordering(self):
        header, chunks = self.fixtures(2)
        self.assertEqual(len(codec.reconstruct(header, list(reversed(chunks)))), 801)

    def test_incomplete_does_not_validate(self):
        header, chunks = self.fixtures(2)
        with self.assertRaisesRegex(ValueError, 'incomplete'):
            codec.reconstruct(header, chunks[:-1])

    def test_hash_integrity(self):
        header, chunks = self.fixtures(1)
        altered = json.loads(json.dumps(chunks))
        altered[0]['records'][0]['path'] = 'tampered'
        with self.assertRaises(ValueError):
            codec.reconstruct(header, altered)

    def test_php_python_canonical_hashes(self):
        for revision in (1, 2):
            _, chunks = self.fixtures(revision)
            for chunk in chunks:
                body = {'records': chunk['records']}
                proc = subprocess.run(
                    ['php', str(ROOT / 'tests/canonical_fixture.php')],
                    input=json.dumps(body, ensure_ascii=False),
                    capture_output=True, text=True, check=True)
                self.assertEqual(proc.stdout, chunk['payload_sha256'])

    def test_receiver_hardwired_test_schema_and_cli(self):
        s = (ROOT / 'receiver/ym-catalog-v2-test-receiver.php').read_text()
        self.assertIn("const DB_NAME = 'yachtmemory_catalog_v2_test'", s)
        self.assertIn("PHP_SAPI !== 'cli'", s)
        self.assertNotIn('dbname=yachtmemory_telemetry', s)


if __name__ == '__main__':
    unittest.main()
