"""IMM5009 real-template binding, hostile payloads and incremental preservation."""
import hashlib
import json
import os
import subprocess
import sys
from pathlib import Path
import tempfile
import unittest
import pikepdf
from lxml import etree as E

BASE = Path(__file__).resolve().parents[2]


class Imm5009Tests(unittest.TestCase):
    def test_download_subprocess_without_windows_systemroot(self):
        if os.name != 'nt':
            return
        env = {key:value for key,value in os.environ.items() if key.lower() != 'systemroot'}
        with tempfile.TemporaryDirectory() as tmp:
            payload = Path(tmp)/'payload.json'
            payload.write_text(json.dumps({'form':'IMM5009','language':'en','fields':{}}),encoding='utf-8')
            output = Path(tmp)/'draft.pdf'
            result = subprocess.run([sys.executable,str(Path(__file__).with_name('prefill_imm_xfa_pdf.py')),str(payload),str(output),str(BASE/'storage/app/imm/imm5009e.pdf')],env=env,capture_output=True,text=True,timeout=60)
            self.assertEqual(0,result.returncode,result.stderr)
            self.assertTrue(output.read_bytes().startswith(b'%PDF-'))

    def test_all_targets_roundtrip_and_preserve_signed_packets(self):
        from imm5009_pdf import fill_document_request, resolve
        for lang, suffix in [('en', 'e'), ('fr', 'f')]:
            c = json.loads(Path(__file__).with_name(f'imm5009-contract.{lang}.json').read_text(encoding='utf-8'))
            fields = {}
            for key, meta in c['fields'].items():
                fields[key] = next(iter(meta['choices'].values())) if meta['choices'] else '2000-01-01' if meta['value_type'] == 'date' else '1' if meta['value_type'] in ['integer','decimal','float'] or meta['max_chars'] < 6 else 'Élodie'
            for target,path in c['targets'].items():
                if target.endswith(('_issue','_expiry','_date')) or target == 'dob': fields[path]='2000-01-01'
                if target.endswith(('_country_code','_extension')): fields[path]='1'
                if target in ['phone_number','alternate_phone_number']: fields[path]='4165550101'
            for rows in c['groups'].values():
                for row in rows:
                    if 'dob' in row: fields[row['dob']]='2000-01-01'
            blank = BASE / f'storage/app/imm/imm5009{suffix}.pdf'
            with tempfile.TemporaryDirectory() as tmp:
                out = Path(tmp)/'draft.pdf'
                fill_document_request({'form':'IMM5009','language':lang,'fields':fields},out,blank)
                self.assertTrue(out.read_bytes().startswith(blank.read_bytes()))
                with pikepdf.open(blank) as original, pikepdf.open(out) as draft:
                    def packets(pdf):
                        x=pdf.Root.AcroForm.XFA
                        return {str(x[i]):x[i+1].read_bytes() for i in range(0,len(x),2)}
                    before, after = packets(original), packets(draft)
                    for name in before:
                        if name not in ['datasets','form']:
                            self.assertEqual(before[name], after[name], name)
                    self.assertEqual(str(original.Root.Perms),str(draft.Root.Perms))
                    data=E.fromstring(after['datasets'])
                    for key,value in fields.items(): self.assertEqual(value,resolve(data,key).text,key)
                    for key in c['manual']: self.assertEqual(resolve(E.fromstring(before['datasets']),key).text,resolve(data,key).text,key)
                    from imm0008_xfa_checksum import form_checksum
                    self.assertEqual(form_checksum(after['template'],after['datasets']),E.fromstring(after['form']).get('checksum'))
                    self.assertFalse(E.fromstring(after['form']).xpath('//*[local-name()="exclGroup"]/*[local-name()="value"]'))

    def test_empty_fields_and_malformed_payloads(self):
        from imm5009_pdf import fill_document_request
        blank=BASE/'storage/app/imm/imm5009e.pdf'
        digest=hashlib.sha256(blank.read_bytes()).hexdigest()
        with tempfile.TemporaryDirectory() as tmp:
            for i,fields in enumerate([{},[]]):
                fill_document_request({'form':'IMM5009','fields':fields},Path(tmp)/f'{i}.pdf',blank)
            for fields in [None,'text',[{'bad':'value'}],{'unknown':'value'},{'IMM_5009.page1.passportGroup':'invalid'},{'IMM_5009.page1.Surname':{}},{'IMM_5009.page1.Surname':'x'*2001},{'IMM_5009.page1.TextField1[0]':'CAD'},{'IMM_5009.page1.TextField1[0]':'NaN'}]:
                with self.assertRaises(ValueError):fill_document_request({'form':'IMM5009','fields':fields},Path(tmp)/'bad.pdf',blank)
            with self.assertRaises(ValueError):fill_document_request({'form':'IMM5009','fields':{}},blank,blank)
            with self.assertRaises(ValueError):fill_document_request({'form':'IMM5009','language':'xx','fields':{}},Path(tmp)/'bad.pdf',blank)
        self.assertEqual(digest,hashlib.sha256(blank.read_bytes()).hexdigest())


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