#!/usr/bin/env python3
"""Where write_marketing_version() persists the bump.

The interesting case is a repo that keeps an xcodegen spec *and* commits the
generated .xcodeproj: auto_detect only runs `xcodegen generate` when no
.xcodeproj is present, so a bump written to the spec alone never reaches
xcodebuild and the archive ships the stale version.
"""

from __future__ import annotations

import os
import tempfile
import unittest
from pathlib import Path
from unittest import mock

import version_utils


PBXPROJ = """// !$*UTF8*$!
{
\t\t\t\tCURRENT_PROJECT_VERSION = 1;
\t\t\t\tMARKETING_VERSION = 0.1.0;
}
"""

SPEC = """name: EmreForms
targets:
  EmreForms:
    settings:
      base:
        MARKETING_VERSION: 0.1.0
"""


class WriteMarketingVersionTest(unittest.TestCase):
    def setUp(self) -> None:
        self.temp = tempfile.TemporaryDirectory()
        self.root = Path(self.temp.name)
        self.project = self.root / "EmreForms.xcodeproj"
        self.project.mkdir()
        self.pbxproj = self.project / "project.pbxproj"
        self.pbxproj.write_text(PBXPROJ, encoding="utf-8")
        self.spec = self.root / "project.yml"
        self.previous = Path.cwd()
        os.chdir(self.root)
        self.env = mock.patch.dict(
            os.environ,
            {"PROJECT": str(self.project), "WORKSPACE": "", "RUNNER_TEMP": ""},
        )
        self.env.start()
        # _record_bumped_path shells out to `git add`; irrelevant here.
        self.record = mock.patch.object(version_utils, "_record_bumped_path")
        self.record.start()

    def tearDown(self) -> None:
        self.record.stop()
        self.env.stop()
        os.chdir(self.previous)
        self.temp.cleanup()

    def test_spec_and_committed_pbxproj_are_kept_in_sync(self) -> None:
        self.spec.write_text(SPEC, encoding="utf-8")

        self.assertTrue(version_utils.write_marketing_version("0.2.0"))

        self.assertIn("MARKETING_VERSION: 0.2.0", self.spec.read_text())
        self.assertIn("MARKETING_VERSION = 0.2.0;", self.pbxproj.read_text())

    def test_pbxproj_alone_is_written_without_a_spec(self) -> None:
        self.assertTrue(version_utils.write_marketing_version("0.2.0"))

        self.assertIn("MARKETING_VERSION = 0.2.0;", self.pbxproj.read_text())

    def test_spec_write_still_succeeds_without_a_generated_project(self) -> None:
        # The usual xcodegen flow: the .xcodeproj is gitignored, so there is
        # nothing to sync and the spec is the only source of truth.
        self.spec.write_text(SPEC, encoding="utf-8")
        self.pbxproj.unlink()

        self.assertTrue(version_utils.write_marketing_version("0.2.0"))

        self.assertIn("MARKETING_VERSION: 0.2.0", self.spec.read_text())

    def test_refuses_the_pbxproj_when_the_spec_lacks_the_key(self) -> None:
        # Unchanged behaviour: a spec that does not declare MARKETING_VERSION
        # means we cannot tell where the value really lives, so we refuse
        # rather than edit a file the next regenerate would overwrite.
        self.spec.write_text("name: EmreForms\n", encoding="utf-8")

        with mock.patch.object(
            version_utils, "_write_xcconfig_marketing_version", return_value=False
        ):
            self.assertFalse(version_utils.write_marketing_version("0.2.0"))

        self.assertIn("MARKETING_VERSION = 0.1.0;", self.pbxproj.read_text())


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