"""Network overlays replace owned bindings, without starting Docker services."""
import copy
import json
from pathlib import Path
import shutil
import subprocess
import tempfile
import unittest

from field_runtime import network_overlay


def fixture():
    return {'services': {
        'redis': {'image': 'redis:7', 'ports': [{'host_ip': '192.0.2.10', 'target': 6379,
                                               'published': '16379', 'protocol': 'tcp'}]},
        'ai-gateway': {'image': 'nginx:alpine', 'ports': [{'target': 38443,
                                                        'published': '38443', 'protocol': 'tcp'}]},
        'analytics': {'image': 'example:existing', 'environment': {'TEXT': 'a: b # c\nquote="x"'},
                      'volumes': ['sample:/data']}}, 'volumes': {'sample': {}}}


class NetworkOverlayTests(unittest.TestCase):
    def test_only_owned_ports_are_tagged_and_input_is_unchanged(self):
        doc = fixture(); before = copy.deepcopy(doc)
        text = network_overlay(doc).decode()
        self.assertEqual(doc, before)
        self.assertEqual(text.count('!override'), 2)
        self.assertIn(json.dumps(doc['services']['analytics']['environment']), text)

    @unittest.skipUnless(shutil.which('docker'), 'Docker Compose is required for render-only test')
    def test_compose_replaces_ip_and_gateway_port_and_preserves_other_fields(self):
        base = fixture(); desired = copy.deepcopy(base)
        desired['services']['redis']['ports'][0]['host_ip'] = '192.0.2.20'
        desired['services']['ai-gateway']['ports'][0].update(target=39443, published='39443')
        with tempfile.TemporaryDirectory() as tmp:
            root = Path(tmp)
            paths = [root / name for name in ('base.json', 'desired.json', 'overlay.yaml')]
            paths[0].write_text(json.dumps(base)); paths[1].write_text(json.dumps(desired))
            paths[2].write_bytes(network_overlay(desired))
            def render(files):
                cmd = ['docker', 'compose', '-p', 'ct-overlay-test']
                for path in files: cmd += ['-f', str(path)]
                result = subprocess.run(cmd + ['config', '--format', 'json'], check=True,
                                        capture_output=True, text=True, timeout=15)
                return json.loads(result.stdout)
            expected = render([paths[1]])
            self.assertEqual(render([paths[0], paths[2]]), expected)
            self.assertEqual(render([paths[1], paths[2]]), expected)


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