"""Stored XFA proof only; Reader rendering/Validate remains manual."""
import json
from pathlib import Path
from contextlib import contextmanager
from uuid import uuid4
import unittest
import xml.etree.ElementTree as E

import pikepdf
from prefill_imm_xfa_pdf import fill, find_by_path
from imm5257sch1_pdf import named, parse

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


@contextmanager
def workdir():
    # tempfile's chmod(0700) produces inaccessible ACLs in managed Windows sandboxes.
    path=BASE/'storage/app/imm/tmp'/('sch1-test-'+uuid4().hex)
    path.mkdir()
    yield str(path)


def packets(path):
    with pikepdf.open(path) as pdf:
        a=pdf.Root.AcroForm.XFA
        return {str(a[i]):a[i+1].read_bytes() for i in range(0,len(a),2)}


class ScheduleWriterTest(unittest.TestCase):
    def payload(self, lang, count):
        contract=json.loads((BASE/f'resources/imm/imm5257sch1-contract.{lang}.json').read_text(encoding='utf-8'))
        tables=list(contract['tables'])
        fields={}
        for pattern,meta in contract['fields'].items():
            for row in range(count) if '{row}' in pattern else [0]:
                path=pattern.replace('{row}',str(row))
                value='Confirmed '+str(row)
                if path.endswith('.PrincipalApplicant'):value='true'
                elif 'allowed_values' in meta:value='true' if count else 'false'
                elif path.endswith('.UCI'):value='12345678'
                elif path.endswith('.Year'):value='1994' if 'ApplicantBirthDate' in path else '2024'
                elif path.endswith('.Month'):value='08' if 'ApplicantBirthDate' in path else '01'
                elif path.endswith('.Day'):value='20'
                elif 'choices' in meta:value=next(iter(meta['choices']))
                fields[path]=value
        return {'form':'IMM5257SCH1','language':lang,'fields':fields,'schedule_rows':dict.fromkeys(['military','ill_treatment','organizations','government','travel'],count)},contract

    def test_zero_one_default_and_overflow_preserve_values_and_scripts(self):
        with workdir() as work:
            for lang,suffix in [('en','e'),('fr','f')]:
                blank=BASE/f'storage/app/imm/imm5257_1{suffix}.pdf'
                original=packets(blank)
                for count in [0,1,4,7]:
                    payload,contract=self.payload(lang,count)
                    # Invalid middle row dates omitted; later indexes must remain stable.
                    if count==7:
                        for key in list(payload['fields']):
                            if '[2].From.' in key or '[2].To.' in key:del payload['fields'][key]
                    src=Path(work)/'payload.json';src.write_text(json.dumps(payload),encoding='utf-8')
                    out=Path(work)/f'{lang}-{count}.pdf'
                    fill(str(src),str(out),str(blank))
                    actual=packets(out)
                    self.assertEqual(original['template'],actual['template'])
                    for packet in ['config','localeSet','connectionSet','schema','PDFSecurity']:
                        self.assertEqual(original[packet],actual[packet])
                    data=E.fromstring(actual['datasets']).find('{http://www.xfa.org/schema/xfa-data/1.0/}data');form=parse(actual['form'])
                    for path,value in payload['fields'].items():
                        nodes=find_by_path(data,path)
                        self.assertEqual(len(nodes),1,path)
                        self.assertEqual(nodes[0].text,value,path)
                    for pattern,meta in contract['tables'].items():
                        path=pattern.replace('[{row}]','')
                        self.assertEqual(len(data.findall(path.replace('.', '/'))),count,path)
                        self.assertEqual(len(named(form,meta['template_path'])),count,path)
                    for part in ['Year','Month','Day']:
                        self.assertFalse(find_by_path(data,'Schedule1.ApplicationValidationDate.'+part)[0].text)
                    self.assertFalse(find_by_path(data,'Schedule1.FormValidated')[0].text)

    def test_unallowlisted_nodes_exports_and_row_indexes_rejected(self):
        with workdir() as work:
            blank=BASE/'storage/app/imm/imm5257_1e.pdf'
            for path,value in [('Schedule1.Untrusted','X'),('Schedule1.PrincipalApplicant','Y'),('Schedule1.MilitaryServiceInfo.MilitaryServiceDetails.MilitaryServiceDetail[99].Location','X')]:
                payload,_=self.payload('en',1);payload['fields'][path]=value
                src=Path(work)/'payload.json';src.write_text(json.dumps(payload),encoding='utf-8')
                with self.assertRaises(ValueError):fill(str(src),str(Path(work)/'invalid.pdf'),str(blank))


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