"""Run the action's signing-to-maintenance steps against a protected Git remote."""
from pathlib import Path
import subprocess
import textwrap

from source_maintenance_fixture import MaintenanceFixture
from test_action_step_order import step_block, step_names


ACTION = Path(__file__).resolve().parents[1]
PREPARE = "Prepare signing (cert + keychain + per-target profiles + pbxproj)"
RERAISE = "Re-raise signing preparation failure"
FILES = ("cert.p12", "cert.meta.json", "cert.registry.json", "profiles.manifest.json",
         "profiles/app.mobileprovision")


class SigningSourceBoundaryTests(MaintenanceFixture):
    def setUp(self):
        super().setUp()
        snapshot = self.root / "action"
        scripts = snapshot / "scripts"
        scripts.mkdir(parents=True)
        (scripts / "prepare_signing.py").write_text(
            "from pathlib import Path\nimport os\n"
            f"for name in {FILES!r}:\n"
            " p = Path('creds') / name\n p.parent.mkdir(parents=True, exist_ok=True)\n"
            " p.write_text('synthetic-signing-material')\n"
            "p = Path('project.yml')\np.write_text(p.read_text() + 'signing: ephemeral\\n')\n"
            "raise SystemExit(int(os.environ.get('FIXTURE_SIGNING_EXIT', '0')))\n")
        (self.repo / ".git/info/exclude").write_text("creds/\n")
        self.env.update({"SWIFT_APP_ACTION": str(snapshot), "RUNNER_TEMP": str(self.root),
                         "GITHUB_ENV": str(self.root / "environment"),
                         "BOT_SCRIPTS_DIR": str(ACTION / "scripts")})
        self.source = (ACTION / "action.yml").read_text()

    def run_signing_to_maintenance(self):
        names = step_names(self.source)
        selected = names[names.index(PREPARE):names.index(RERAISE)]
        result = None
        for name in selected:
            block = step_block(self.source, name)
            script = textwrap.dedent(block.split("      run: ", 1)[1])
            if script.startswith("|\n"):
                script = textwrap.dedent(script[2:])
            result = subprocess.run(["bash", "-e", "-o", "pipefail", "-c", script],
                                    cwd=self.repo, env=self.env, capture_output=True, text=True, timeout=15)
            if result.returncode:
                return result
        return result

    def assert_ephemeral_signing(self):
        for name in FILES:
            self.assertEqual((self.repo / "creds" / name).read_text(), "synthetic-signing-material")
        self.assertEqual(self.git("ls-files", "creds"), "")
        self.assertEqual(self.git("diff", "--cached", "--name-only"), "")
        self.assertEqual(self.git("rev-parse", "HEAD").strip(), self.base)

    def test_legacy_true_input_keeps_signing_out_of_version_candidate(self):
        # All steps for archive=true/default-branch push/persist-signing-cache=true run.
        self.stage()
        receipt = self.receipt(self.run_signing_to_maintenance())
        self.assertEqual(self.git("diff", "--name-only", self.base, receipt["head_sha"]), "project.yml\n")
        self.assertEqual(self.git("show", receipt["head_sha"] + ":project.yml"), "version: 1.1\n")
        self.assertEqual((self.repo / "project.yml").read_text(), "version: 1.1\nsigning: ephemeral\n")
        self.assert_ephemeral_signing()

    def test_signing_without_source_changes_needs_no_maintenance_candidate(self):
        result = self.run_signing_to_maintenance()
        self.assertEqual(result.returncode, 0, result.stderr)
        self.assertEqual(len(self.git("ls-remote", "--heads", "origin").splitlines()), 1)
        self.assert_ephemeral_signing()

    def test_signing_failure_stays_visible_after_source_preservation(self):
        self.stage()
        self.env["FIXTURE_SIGNING_EXIT"] = "7"
        self.receipt(self.run_signing_to_maintenance())
        self.assertIn("SIGNING_PREP_EXIT=7\n", Path(self.env["GITHUB_ENV"]).read_text())
        script = textwrap.dedent(step_block(self.source, RERAISE).split("      run: |\n", 1)[1])
        result = subprocess.run(["bash", "-e", "-c", script], cwd=self.repo,
                                env={**self.env, "SIGNING_PREP_EXIT": "7"}, capture_output=True, text=True)
        self.assertEqual(result.returncode, 7)
        self.assert_ephemeral_signing()
