"""Adversarial and boundary checks for Ocean6's local reference, no network."""
import copy
import json
import tempfile
from pathlib import Path
import subprocess
import sys
import unittest
from reference_runtime import execute, compare, encode, digest, strict_json, verify

class ReferenceTests(unittest.TestCase):
    def task(self, **values):
        task={'version':'0.2','operation':'literal-line-search','document':'Alpha\r\nalpha 交付\r交付\n\nALPHA','terms':['Alpha','交付',' alpha '],'top_k':2}
        task.update(values)
        return task

    def test_ranking_line_numbers_and_deduplication(self):
        result=execute(self.task())
        self.assertEqual(result['total_matches'],4)
        self.assertEqual(result['matches'],[
            {'line':2,'score':2,'text':'alpha 交付','matched_terms':['alpha','交付']},
            {'line':1,'score':1,'text':'Alpha','matched_terms':['alpha']}])

    def test_no_matches_is_empty(self):
        self.assertEqual(execute(self.task(terms=['不存在']))['matches'],[])

    def test_utf8_byte_limit(self):
        execute(self.task(document='a'*20000))
        with self.assertRaisesRegex(ValueError,'INVALID_DOCUMENT'):
            execute(self.task(document='中'*6667))

    def test_unicode_and_ascii_only_case_fold(self):
        result=execute(self.task(document='Ä\nä\n😀\n<span>ALPHA</span>',terms=['ä','😀','alpha'],top_k=10))
        self.assertEqual([r['line'] for r in result['matches']],[2,3,4])
        self.assertEqual(result['matches'][-1]['text'],'<span>ALPHA</span>')

    def test_reject_invalid_inputs(self):
        for values in [{'top_k':True},{'top_k':0},{'top_k':1.5},{'top_k':11},{'document':''},{'document':'\ud800'},{'terms':[' ']},{'terms':['a\nb']},{'terms':['x']*17},{'operation':'shell'},{'extra':'bad'}]:
            with self.subTest(values=values),self.assertRaises(ValueError):
                execute(self.task(**values))

    def test_replay_rejects_changed_results_and_boolean_coercion(self):
        task=encode(self.task()); result=execute(self.task())
        self.assertTrue(compare(task,encode(result)))
        result['matches'][0]['text']='forged'
        with self.assertRaisesRegex(ValueError,'REPLAY_MISMATCH'):compare(task,encode(result))
        task=encode(self.task(document='alpha',terms=['alpha']))
        result=execute(strict_json(task));result['total_matches']=True
        with self.assertRaisesRegex(ValueError,'REPLAY_MISMATCH'):compare(task,encode(result))

    def test_json_order_irrelevant_but_extra_fields_rejected(self):
        task=encode(self.task());result=execute(self.task())
        self.assertTrue(compare(task,json.dumps(result,sort_keys=True).encode()))
        result['extra']=None
        with self.assertRaisesRegex(ValueError,'REPLAY_MISMATCH'):compare(task,encode(result))

    def test_duplicate_keys_rejected(self):
        with self.assertRaisesRegex(ValueError,'DUPLICATE_JSON_KEY'):strict_json('{"a":1,"a":2}')

    def test_cli_receipt_and_digest_binding(self):
        with tempfile.TemporaryDirectory() as temp:
            path=Path(temp);task=path/'task.json';result=path/'result.json';receipt=path/'receipt.json'
            task.write_bytes(encode(self.task()))
            command=[sys.executable,str(Path(__file__).with_name('reference_runtime.py'))]
            subprocess.run(command+['run',str(task),str(result),str(receipt)],check=True,capture_output=True)
            subprocess.run(command+['verify',str(task),str(result),str(receipt)],check=True,capture_output=True)
            self.assertTrue(verify(task.read_bytes(),result.read_bytes(),receipt.read_bytes()))
            with self.assertRaisesRegex(ValueError,'TASK_DIGEST_MISMATCH'):
                verify(task.read_bytes()+b'\n',result.read_bytes(),receipt.read_bytes())
            with self.assertRaisesRegex(ValueError,'RESULT_DIGEST_MISMATCH'):
                verify(task.read_bytes(),result.read_bytes()+b'\n',receipt.read_bytes())
            changed=strict_json(receipt.read_bytes());changed['signature']='pretend'
            with self.assertRaisesRegex(ValueError,'INVALID_RECEIPT_SCOPE'):
                verify(task.read_bytes(),result.read_bytes(),encode(changed))
            changed=strict_json(receipt.read_bytes());changed['finished_at']='2000-01-01T00:00:00.000000Z'
            with self.assertRaisesRegex(ValueError,'INVALID_TIME_ORDER'):
                verify(task.read_bytes(),result.read_bytes(),encode(changed))

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