"""IMM1294 phone merge regression checks; Adobe rendering stays manual."""
import json
from pathlib import Path
import re
import unittest
from uuid import uuid4

import pikepdf
from lxml import etree as E
from prefill_imm_xfa_pdf import fill, find_by_path

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


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


def named(root, path):
    node = root
    for part in path.split('.'):
        node = next(child for child in node if child.get('name') == part)
    return node


class Imm1294PhoneStateTest(unittest.TestCase):
    def setUp(self):
        self.work = BASE / 'storage/app/imm/tmp' / ('1294-phone-' + uuid4().hex)
        self.work.mkdir(parents=True)

    def test_byte_patch_only_changes_confirmed_phone_branch_presence(self):
        from imm1294_pdf_state import contact_phone_state
        raw = (b'<template xmlns="urn:test"><?keep exact?><subform name="form1">'
               b'<subform name="Page3"><subform name="PhoneNumbers"><subform name="Phone">'
               b'<subform name="NANumber" presence="invisible"/>'
               b'<subform name="IntlNumber"/><script>value &lt; 2;</script>'
               b'</subform><subform name="AltPhone"><subform name="NANumber" presence="invisible"/>'
               b'</subform></subform></subform></subform></template>')
        fields = {'PhoneNumbers.Phone.CanadaUS': '1', 'PhoneNumbers.Phone.Other': '0'}
        expected = raw.replace(b'name="NANumber" presence="invisible"', b'name="NANumber" presence="visible"', 1)
        expected = expected.replace(b'name="IntlNumber"/>', b'name="IntlNumber" presence="invisible"/>', 1)
        self.assertEqual(contact_phone_state(raw, fields), expected)
        for fields in ({}, {'PhoneNumbers.Phone.ActualNumber': '+94771234567'},
                       {'PhoneNumbers.Phone.CanadaUS': '1'},
                       {'PhoneNumbers.Phone.CanadaUS': '1', 'PhoneNumbers.Phone.Other': '1'},
                       {'PhoneNumbers.Phone.CanadaUS': '0', 'PhoneNumbers.Phone.Other': '0'}):
            self.assertEqual(contact_phone_state(raw, fields), raw)

    def test_bilingual_phone_branches_follow_confirmed_exports(self):
        for language, suffix in [('en', 'e'), ('fr', 'f')]:
            blank = BASE / f'storage/app/imm/imm1294{suffix}.pdf'
            original = packets(blank)
            for canada in (True, False):
                fields = {}
                for group in ('Phone', 'AltPhone'):
                    prefix = 'PhoneNumbers.' + group + '.'
                    fields.update({prefix + 'CanadaUS': '1' if canada else '0',
                                   prefix + 'Other': '0' if canada else '1',
                                   prefix + 'NumberCountry': '1' if canada else '94',
                                   prefix + 'ActualNumber': '4165550100' if canada else '+94771234567'})
                    if canada:
                        fields.update({prefix + 'NANumber.AreaCode': '416', prefix + 'NANumber.FirstThree': '555', prefix + 'NANumber.LastFive': '0100'})
                    else:
                        fields[prefix + 'IntlNumber.IntlNumber'] = '771234567'
                snapshot = dict(fields)
                payload = self.work / 'payload.json'
                output = self.work / f'{language}-{canada}.pdf'
                payload.write_text(json.dumps({'form': 'IMM1294', 'language': language, 'fields': fields}), encoding='utf-8')
                fill(str(payload), str(output), str(blank))
                written = packets(output)
                for packet in ('template', 'form'):
                    root = E.fromstring(written[packet])
                    for group in ('Phone', 'AltPhone'):
                        prefix = ('form1.Page3.' if language == 'en' else 'form1.Page2.contact.') + 'PhoneNumbers.' + group + '.'
                        self.assertEqual(named(root, prefix + 'NANumber').get('presence'), 'visible' if canada else 'invisible')
                        self.assertEqual(named(root, prefix + 'IntlNumber').get('presence'), 'invisible' if canada else 'visible')
                    before = E.fromstring(original[packet])
                    self.assertEqual(before.xpath('//*[local-name()="script"]/text()'), root.xpath('//*[local-name()="script"]/text()'))
                    self.assertEqual(re.findall(br'<\?.*?\?>', original[packet], re.S), re.findall(br'<\?.*?\?>', written[packet], re.S))
                for packet in original:
                    if packet not in ('template', 'form', 'datasets'):
                        self.assertEqual(original[packet], written[packet], packet)
                data = E.fromstring(written['datasets'])
                for path, value in fields.items():
                    self.assertEqual(find_by_path(data, path)[0].text, value, path)
                self.assertEqual(fields, snapshot)
                self.assertEqual(original, packets(blank))

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