"""Actual PHP mapper JSON must survive the reviewed PDF writer handoff."""
import json
from pathlib import Path
import subprocess
import tempfile
import unittest

import pikepdf

from prefill_imm_xfa_pdf import fill

BASE = Path(__file__).resolve().parents[2]
FORMS = {'IMM5669': 'imm5669', 'IMM5406': 'imm5406', 'IMM5257SCH1': 'imm5257_1'}


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)}


class EmptyFieldsHandoffTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        # Preserve the exact json_encode result, including PHP's empty [] type.
        script = r'''
require 'vendor/autoload.php';
$app = require 'bootstrap/app.php';
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
$bag = new App\Services\Imm\ImmQuestionnaireAnswerBag([], null, null);
$results = [];
foreach (['IMM5669', 'IMM5406', 'IMM5257SCH1'] as $form) {
    foreach (['en', 'fr'] as $language) {
        $payload = (new App\Services\Imm\ImmFormPrefillMapper($bag))->build($form, $language);
        $results[$form.'-'.$language] = json_encode($payload, JSON_THROW_ON_ERROR);
    }
}
echo json_encode($results, JSON_THROW_ON_ERROR);
'''
        result = subprocess.run(['php', '-r', script], cwd=BASE, text=True,
                                capture_output=True, check=True, timeout=60)
        cls.serialized = json.loads(result.stdout)

    def test_unanswered_php_payloads_generate_equivalent_empty_object_pdfs(self):
        with tempfile.TemporaryDirectory(dir=BASE / 'storage/app/imm/tmp') as work:
            work = Path(work)
            for key, serialized in self.serialized.items():
                with self.subTest(payload=key):
                    payload = json.loads(serialized)
                    self.assertEqual(payload['fields'], [])
                    self.assertTrue(payload['review_items'])
                    stem = FORMS[payload['form']]
                    suffix = 'e' if payload['language'] == 'en' else 'f'
                    blank = BASE / f'storage/app/imm/{stem}{suffix}.pdf'
                    source, output, control = work/'php.json', work/'php.pdf', work/'object.pdf'
                    source.write_text(serialized, encoding='utf-8')
                    fill(source, output, blank)
                    payload['fields'] = {}
                    source.write_text(json.dumps(payload), encoding='utf-8')
                    fill(source, control, blank)
                    actual = packets(output)
                    self.assertEqual(actual, packets(control))
                    self.assertEqual(actual['template'], packets(blank)['template'])

    def test_nonempty_arrays_and_other_invalid_fields_still_fail(self):
        with tempfile.TemporaryDirectory(dir=BASE / 'storage/app/imm/tmp') as work:
            work = Path(work)
            for form, stem in FORMS.items():
                payload = json.loads(self.serialized[form+'-en'])
                for invalid in ([{'untrusted': 'value'}], None, False, '', 0):
                    with self.subTest(form=form, invalid=invalid):
                        payload['fields'] = invalid
                        source = work/'invalid.json'
                        source.write_text(json.dumps(payload), encoding='utf-8')
                        with self.assertRaises(ValueError):
                            fill(source, work/'invalid.pdf', BASE/f'storage/app/imm/{stem}e.pdf')


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