"""Exercise promoted binaries with current credentials and preserved version/symbol identity."""
import contextlib
import io
import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
import tempfile
import unittest
from unittest.mock import patch

import mobile_artifact_files as artifact


class RestoreTests(unittest.TestCase):
    def setUp(self):
        self.temporary = tempfile.TemporaryDirectory()
        self.addCleanup(self.temporary.cleanup)
        self.root = Path(self.temporary.name)
        self.creds = self.root / "creds"
        self.creds.mkdir()
        (self.root / "event.json").write_text("{}")
        (self.root / "output").touch()
        self.retained = self.root / "retained"
        self.retained.mkdir()
        environment = {"RUNNER_TEMP": str(self.root), "GITHUB_WORKSPACE": str(self.root),
                       "GITHUB_EVENT_PATH": str(self.root / "event.json"),
                       "GITHUB_OUTPUT": str(self.root / "output"), "GITHUB_ENV": str(self.root / "environment"),
                       "GITHUB_REPOSITORY": "owned/app", "GITHUB_SHA": "a" * 40,
                       "GITHUB_RUN_ID": "123", "GITHUB_RUN_ATTEMPT": "1",
                       "MOBILE_ARTIFACT_FINGERPRINT": "f" * 64}
        self.environment = patch.dict(os.environ, environment)
        self.environment.start()
        self.addCleanup(self.environment.stop)

    def test_installed_android_restore_uses_current_account_and_frozen_bundle(self):
        account = self.creds / "play.json"
        account.write_text(json.dumps({"type": "service_account", "client_email": "fixture@example.test",
                                       "private_key": "fixture-only-not-a-key"}))
        (self.creds / "upload.jks").write_bytes(b"fixture-keystore")
        properties = self.creds / "android-signing.properties"
        properties.write_text("storePassword=fixture\nkeyPassword=fixture\nkeyAlias=upload\n")
        binary = self.root / "signed.aab"
        binary.write_bytes(b"signed-fixture")
        with patch.dict(os.environ, {"ANDROID_PACKAGE_NAME": "com.owned.app", "ANDROID_BUILD_NUMBER": "42",
                                     "ANDROID_PROJECT_KIND": "gradle", "MOBILE_ARTIFACT_BINARY": str(binary)}):
            artifact.pack("android", self.retained)
        scripts = self.root / "installed/swift-app/scripts"
        scripts.mkdir(parents=True)
        shutil.copyfile(Path(artifact.__file__), scripts / "mobile_artifact_files.py")
        android = scripts.parents[1] / "android-app/scripts"
        android.mkdir(parents=True)
        shutil.copyfile(Path(artifact.__file__).resolve().parents[2] / "android-action/scripts/android_config.py",
                        android / "android_config.py")
        command = [sys.executable, str(scripts / "mobile_artifact_files.py"), "restore", "android", str(self.retained)]
        subprocess.run(command, check=True, capture_output=True, text=True)
        output = (self.root / "output").read_text()
        self.assertIn(str(account), output)
        self.assertIn(str(self.retained / "app.aab"), output)
        self.assertIn("\n42\n", output)
        self.assertNotIn("fixture-only-not-a-key", output)
        properties.write_text(properties.read_text().replace("keyAlias=upload", "keyAlias=other"))
        refused = subprocess.run(command, capture_output=True, text=True)
        self.assertNotEqual(refused.returncode, 0)

    def test_ios_restores_version_and_symbols_with_shipping_run_receipt(self):
        key = self.creds / "AuthKey_ABCDEFGHIJ_Issuer_11111111-2222-3333-4444-555555555555.p8"
        key.write_text("fixture-key-material")
        (self.root / "export").mkdir()
        (self.root / "export/app.ipa").write_bytes(b"signed-fixture")
        symbols = self.root / "firebase-symbols"
        symbols.mkdir()
        (symbols / "dsym.zip").write_bytes(b"fixture-symbols")
        (symbols / "firebase-symbols.json").write_text(json.dumps({"source_sha": "a" * 40, "artifact": "candidate"}))
        values = {"CFG_BUNDLE_ID": "com.owned.app", "CFG_TEAM_ID": "AAAAAAAAAA", "CFG_APP_STORE_APPLE_ID": "123",
                  "BUILD_NUMBER": "42", "MARKETING_VERSION": "1.0.1", "SOURCE_MARKETING_VERSION": "1.0.0",
                  "CFG_WHATS_NEW": "Line one\nLine two"}
        with patch.dict(os.environ, values):
            artifact.pack("ios", self.retained)
        with patch.dict(os.environ, {"GITHUB_RUN_ID": "456", "GITHUB_RUN_ATTEMPT": "2", "GITHUB_SHA": "b" * 40}):
            with contextlib.redirect_stdout(io.StringIO()) as logs:
                artifact.restore("ios", self.retained)
        environment = (self.root / "environment").read_text()
        self.assertIn("REUSED_BUILD_NUMBER<<", environment)
        self.assertIn("\n42\n", environment)
        self.assertNotIn("fixture-key-material", environment)
        self.assertEqual((self.root / "candidate-whats-new.txt").read_text(), "Line one\nLine two")
        receipt = json.loads((symbols / "firebase-symbols.json").read_text())
        self.assertEqual(receipt["artifact"], "ios-crashlytics-symbols-456-2")
        self.assertEqual(receipt["source_sha"], "b" * 40)
        self.assertIn("firebase_symbols_pending", logs.getvalue())
