"""Validate the actual action guards and immutable transport snapshot boundaries."""
from pathlib import Path
import unittest

from test_action_step_order import step_block, step_names

ACTION = Path(__file__).resolve().parents[1] / "action.yml"


class WiringTests(unittest.TestCase):
    def test_flutter_configuration_uses_the_same_bundle_before_pods(self):
        template = ACTION.parents[1] / "templates/deploy.yml"
        body = template.read_text().split("- name: Prepare Flutter iOS project\n", 1)[1].split("\n      - ", 1)[0]
        shell = body.split("shell: >-\n", 1)[1].split("\n        env:", 1)[0]
        self.assertIn(".github/actions/swift-app/scripts/native_bundle.py", shell)
        self.assertIn("--folder ios", shell)
        # CI reaches every provider directly; no transport helper may be reintroduced here.
        self.assertNotIn("proxy", shell.lower())
        self.assertIn("-- bash --noprofile --norc -e -o pipefail {0}", shell)
        self.assertIn("flutter build ios", body)

    def test_every_selected_xcode_step_has_its_own_preflight(self):
        source = ACTION.read_text()
        names = {name: step_block(source, name) for name in step_names(source)}
        for name, operation in (("Run simulator tests", "xcodebuild "),
                                ("Resolve marketing version (project source of truth)", "resolve_marketing_version.py"),
                                ("Stamp Info.plist versions (CFBundleVersion + CFBundleShortVersionString)",
                                 "resolve_info_plist.py"), ("Archive", "xcodebuild ")):
            body = names[name]
            self.assertLess(body.index("native_dependency_guard.py"), body.index(operation))
            self.assertIn('--container "${WORKSPACE:-$PROJECT}"', body)
        resolve = names["Resolve credentials + auto-detect Xcode project"]
        read_config = 'python3 "$SWIFT_APP_ACTION/scripts/read_config.py"'
        self.assertLess(resolve.index("native_pods.py"), resolve.index(read_config))
        self.assertIn('export INPUT_WORKSPACE', resolve)
        snapshot = names["Snapshot this action for the whole run"]
        self.assertIn("$RUNNER_TEMP/swift-app-action", snapshot)
        self.assertNotIn("google-transport", snapshot)

    def test_shell_blocks_parse_without_exec(self):
        import subprocess
        import textwrap
        source = ACTION.read_text()
        for name in step_names(source):
            body = step_block(source, name)
            if "native_dependency_guard.py" in body or "native_pods.py" in body:
                script = textwrap.dedent(body.split("      run: |\n", 1)[1])
                result = subprocess.run(["bash", "-n"], input=script, text=True, capture_output=True)
                self.assertEqual(result.returncode, 0, name)

    def test_real_archive_shell_refuses_remote_graph_before_xcode(self):
        import os
        import subprocess
        import tempfile
        import textwrap
        from test_native_dependency_guard import project
        with tempfile.TemporaryDirectory(prefix="app-robot-native-archive-") as temporary:
            root = Path(temporary).resolve()
            project(root, extra={"remote": {"isa": "XCRemoteSwiftPackageReference"}})
            xcode = root / "xcodebuild"
            xcode.write_text('#!/bin/sh\ntouch "$GITHUB_WORKSPACE/xcode-called"\n')
            xcode.chmod(0o700)
            script = textwrap.dedent(step_block(ACTION.read_text(), "Archive").split("      run: |\n", 1)[1])
            env = {**os.environ, "GITHUB_WORKSPACE": str(root), "SWIFT_APP_ACTION": str(ACTION.parent),
                   "PROJECT": "App.xcodeproj", "WORKSPACE": "", "PATH": str(root) + os.pathsep + os.environ["PATH"]}
            result = subprocess.run(["bash", "-e", "-o", "pipefail", "-c", script],
                                    cwd=root, env=env, capture_output=True, text=True, timeout=10)
            self.assertEqual(result.returncode, 1)
            self.assertIn("native_package_proxy_transport_required", result.stdout)
            self.assertFalse((root / "xcode-called").exists())
