"""Offline tests; set TMPDIR to your intended test volume before running."""
import json
from pathlib import Path
import tempfile
import unittest

from prepare_mission import MAX_CSV_BYTES, mission_source, prepare, published_selection


def descriptor():
    ura = "easynet:///r/test/ability/system-agent.provider.ability-management.office_report.build_sales_report"
    return {"name": "office_report.build_sales_report", "owner_ura": "easynet:///r/test/agent/device.provider.ability-management", "ability_ura": ura, "descriptor_ref": ura + "@1.0.0#" + "a" * 64 + "!invoke", "admission_action": "invoke"}


class PrepareMissionTests(unittest.TestCase):
    def test_escape_csv_without_executing_or_interpolating(self):
        csv = 'quoted " text\\\n$(touch should-not-run)\n'
        source = mission_source(descriptor(), csv)
        self.assertIn("csv_text: " + json.dumps(csv), source)
        self.assertIn("timeout 30 on_failure abort", source)
        self.assertNotIn("retries", source)

    def test_missing_actual_metadata_rejected(self):
        for key in ("name", "owner_ura", "ability_ura", "descriptor_ref"):
            for value in (None, "", 123):
                with self.subTest(key=key, value=value), self.assertRaises(ValueError):
                    published_selection({**descriptor(), key: value})

    def test_wrong_function_or_pin_rejected(self):
        for update in ({"name": "different"}, {"descriptor_ref": "invented"}, {"admission_action": "stream"}):
            with self.subTest(update=update), self.assertRaises(ValueError):
                published_selection({**descriptor(), **update})

    def test_size_limit_is_utf8_bytes(self):
        self.assertIn("mission", mission_source(descriptor(), "x" * MAX_CSV_BYTES))
        for text in ("x" * (MAX_CSV_BYTES + 1), "界" * 11000):
            with self.assertRaises(ValueError):
                mission_source(descriptor(), text)

    def test_creates_only_new_file_and_preserves_existing(self):
        with tempfile.TemporaryDirectory() as temp:
            root = Path(temp)
            meta, csv, output = root / "descriptor.json", root / "input.csv", root / "Mission.eal"
            meta.write_text(json.dumps(descriptor()), encoding="utf-8")
            csv.write_text("fixture\n", encoding="utf-8")
            prepare(meta, csv, output)
            expected = mission_source(descriptor(), "fixture\n")
            self.assertEqual(output.read_text(), expected)
            with self.assertRaises(ValueError):
                prepare(meta, csv, output)
            self.assertEqual(output.read_text(), expected)

    def test_bad_utf8_or_oversized_file_leaves_no_output(self):
        with tempfile.TemporaryDirectory() as temp:
            root = Path(temp)
            meta, csv, output = root / "descriptor.json", root / "input.csv", root / "Mission.eal"
            meta.write_text(json.dumps(descriptor()))
            for data in (b"\xff", b"x" * (MAX_CSV_BYTES + 1)):
                csv.write_bytes(data)
                with self.assertRaises(ValueError):
                    prepare(meta, csv, output)
                self.assertFalse(output.exists())

    def test_dangling_symlink_is_not_overwritten(self):
        with tempfile.TemporaryDirectory() as temp:
            root = Path(temp)
            output = root / "Mission.eal"
            output.symlink_to(root / "missing")
            with self.assertRaises(ValueError):
                prepare(root / "absent-descriptor", root / "absent-input", output)
            self.assertTrue(output.is_symlink())


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