"""Regression for Xcode 26.3 compiling one universal iOS 1024 source icon.

The fixture retains only structural assetutil fields from a real signed archive;
it contains neither artwork nor signing data. Catalog mutations must fail closed.
"""
import json
from pathlib import Path
import sys
import unittest

sys.path.insert(0, str(Path(__file__).resolve().parent))
import delivery_preflight as preflight


def context():
    rows = json.loads((Path(__file__).parent / "fixtures/single-size-ios-icon.json").read_text())
    return {"families": {1, 2}, "renditions": rows, "flattened": {120, 152}}


class SingleSizeIconTests(unittest.TestCase):
    def test_real_compiled_single_size_catalog_covers_phone_pad_and_marketing(self):
        ctx = context()
        self.assertEqual(preflight.check_app_icons(ctx), [])
        self.assertEqual(preflight.check_marketing_icon(ctx), [])

    def test_one_idiom_does_not_cover_the_other_declared_family(self):
        ctx = context()
        ctx["renditions"] = [r for r in ctx["renditions"] if r["Idiom"] == "phone"]
        failures = preflight.check_app_icons(ctx)
        self.assertEqual(len(failures), 2)
        self.assertTrue(all("iPad" in item["message"] for item in failures))
        ctx["families"] = {1}
        self.assertEqual(preflight.check_app_icons(ctx), [])

    def test_large_image_without_multi_size_index_does_not_prove_coverage(self):
        ctx = context()
        ctx["renditions"] = [r for r in ctx["renditions"] if r["AssetType"] == "Icon Image"]
        self.assertEqual(len(preflight.check_app_icons(ctx)), 4)
        self.assertEqual(len(preflight.check_marketing_icon(ctx)), 1)

    def test_index_without_icon_image_does_not_prove_coverage(self):
        ctx = context()
        ctx["renditions"] = [r for r in ctx["renditions"] if r["AssetType"] == "MultiSized Image"]
        self.assertEqual(len(preflight.check_app_icons(ctx)), 4)
        self.assertEqual(len(preflight.check_marketing_icon(ctx)), 1)

    def test_mismatched_catalog_pairs_do_not_cover_the_changed_idiom(self):
        changes = [{"Icon Index": 2}, {"Name": "AppIconOther"}, {"PixelHeight": 512},
                   {"PixelWidth": 512}, {"Scale": 2}, {"AssetType": "Image"},
                   {"Idiom": "unrelated"}]
        for change in changes:
            with self.subTest(change=change):
                ctx = context()
                ctx["renditions"][0].update(change)
                failures = preflight.check_app_icons(ctx)
                self.assertEqual(len(failures), 2)
                self.assertTrue(all("iPhone" in item["message"] for item in failures))

    def test_unrelated_asset_name_cannot_supply_an_app_icon(self):
        ctx = context()
        for row in ctx["renditions"]:
            row["Name"] = "HeroImage"
        self.assertEqual(len(preflight.check_app_icons(ctx)), 4)

    def test_malformed_or_wrong_index_metadata_is_not_coverage(self):
        invalid = [None, "1024x1024 index:1 idiom:phone", ["1024x1024 index:2 idiom:phone"],
                   ["1024x1024 index:1 idiom:pad"], ["512x512 index:1 idiom:phone"]]
        for sizes in invalid:
            with self.subTest(sizes=sizes):
                ctx = context()
                ctx["renditions"][2]["Sizes"] = sizes
                self.assertEqual(len(preflight.check_app_icons(ctx)), 2)


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