from itertools import product

import pytest

from hatch.plugin.constants import DEFAULT_CUSTOM_SCRIPT
from hatch.plugin.manager import PluginManager
from hatch.project.config import ProjectConfig
from hatch.project.constants import DEFAULT_BUILD_DIRECTORY, BuildEnvVars
from hatch.project.env import RESERVED_OPTIONS
from hatch.utils.structures import EnvVars

ARRAY_OPTIONS = [o for o, t in RESERVED_OPTIONS.items() if t is list]
BOOLEAN_OPTIONS = [o for o, t in RESERVED_OPTIONS.items() if t is bool]
MAPPING_OPTIONS = [o for o, t in RESERVED_OPTIONS.items() if t is dict and o != "workspace"]
STRING_OPTIONS = [o for o, t in RESERVED_OPTIONS.items() if t is str and o != "matrix-name-format"]
WORKSPACE_OPTIONS = ["workspace"]  # Workspace has nested structure, tested separately


def construct_matrix_data(env_name, config, overrides=None):
    config = dict(config[env_name])
    config.pop("overrides", None)
    matrices = config.pop("matrix")
    final_matrix_name_format = config.pop("matrix-name-format", "{value}")

    # [{'version': ['9000']}, {'feature': ['bar']}]
    envs = {}
    for matrix_data in matrices:
        matrix = dict(matrix_data)
        variables = {}
        python_selected = False
        for variable in ("py", "python"):
            if variable in matrix:
                python_selected = True
                variables[variable] = matrix.pop(variable)
                break
        variables.update(matrix)

        for result in product(*variables.values()):
            variable_values = dict(zip(variables, result, strict=False))
            env_name_parts = []
            for j, (variable, value) in enumerate(variable_values.items()):
                if j == 0 and python_selected:
                    env_name_parts.append(value if value.startswith("py") else f"py{value}")
                else:
                    env_name_parts.append(final_matrix_name_format.format(variable=variable, value=value))

            new_env_name = "-".join(env_name_parts)
            if env_name != "default":
                new_env_name = f"{env_name}.{new_env_name}"

            envs[new_env_name] = variable_values
            if "py" in variable_values:
                envs[new_env_name] = {"python": variable_values.pop("py"), **variable_values}

    config.update(overrides or {})
    config.setdefault("type", "virtual")
    return {"config": config, "envs": envs}


class TestEnv:
    def test_not_table(self, isolation):
        with pytest.raises(TypeError, match="Field `tool.hatch.env` must be a table"):
            _ = ProjectConfig(isolation, {"env": 9000}).env

    def test_default(self, isolation):
        project_config = ProjectConfig(isolation, {})

        assert project_config.env == project_config.env == {}


class TestEnvRequires:
    def test_not_array(self, isolation):
        with pytest.raises(TypeError, match="Field `tool.hatch.env.requires` must be an array"):
            _ = ProjectConfig(isolation, {"env": {"requires": 9000}}).env_requires

    def test_requirement_not_string(self, isolation):
        with pytest.raises(TypeError, match="Requirement #1 in `tool.hatch.env.requires` must be a string"):
            _ = ProjectConfig(isolation, {"env": {"requires": [9000]}}).env_requires

    def test_requirement_invalid(self, isolation):
        with pytest.raises(ValueError, match="Requirement #1 in `tool.hatch.env.requires` is invalid: .+"):
            _ = ProjectConfig(isolation, {"env": {"requires": ["foo^1"]}}).env_requires

    def test_default(self, isolation):
        project_config = ProjectConfig(isolation, {})

        assert project_config.env_requires_complex == project_config.env_requires_complex == []
        assert project_config.env_requires == project_config.env_requires == []

    def test_defined(self, isolation):
        project_config = ProjectConfig(isolation, {"env": {"requires": ["foo", "bar", "baz"]}})

        assert project_config.env_requires == ["foo", "bar", "baz"]


class TestEnvCollectors:
    def test_not_table(self, isolation):
        with pytest.raises(TypeError, match="Field `tool.hatch.env.collectors` must be a table"):
            _ = ProjectConfig(isolation, {"env": {"collectors": 9000}}).env_collectors

    def test_collector_not_table(self, isolation):
        with pytest.raises(TypeError, match="Field `tool.hatch.env.collectors.foo` must be a table"):
            _ = ProjectConfig(isolation, {"env": {"collectors": {"foo": 9000}}}).env_collectors

    def test_default(self, isolation):
        project_config = ProjectConfig(isolation, {})

        assert project_config.env_collectors == project_config.env_collectors == {"default": {}}

    def test_defined(self, isolation):
        project_config = ProjectConfig(isolation, {"env": {"collectors": {"foo": {"bar": {"baz": 9000}}}}})

        assert project_config.env_collectors == {"default": {}, "foo": {"bar": {"baz": 9000}}}
        assert list(project_config.env_collectors) == ["default", "foo"]


class TestEnvs:
    def test_not_table(self, isolation):
        with pytest.raises(TypeError, match="Field `tool.hatch.envs` must be a table"):
            _ = ProjectConfig(isolation, {"envs": 9000}, PluginManager()).envs

    def test_config_not_table(self, isolation):
        with pytest.raises(TypeError, match="Field `tool.hatch.envs.foo` must be a table"):
            _ = ProjectConfig(isolation, {"envs": {"foo": 9000}}, PluginManager()).envs

    def test_unknown_collector(self, isolation):
        with pytest.raises(ValueError, match="Unknown environment collector: foo"):
            _ = ProjectConfig(isolation, {"env": {"collectors": {"foo": {}}}}, PluginManager()).envs

    def test_unknown_template(self, isolation):
        with pytest.raises(
            ValueError, match="Field `tool.hatch.envs.foo.template` refers to an unknown environment `bar`"
        ):
            _ = ProjectConfig(isolation, {"envs": {"foo": {"template": "bar"}}}, PluginManager()).envs

    def test_default_undefined(self, isolation):
        project_config = ProjectConfig(isolation, {}, PluginManager())

        assert project_config.envs == project_config.envs == {"default": {"type": "virtual"}}
        assert project_config.matrices == project_config.matrices == {}

    def test_default_partially_defined(self, isolation):
        env_config = {"default": {"option": True}}
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        assert project_config.envs == {"default": {"option": True, "type": "virtual"}}

    def test_default_defined(self, isolation):
        env_config = {"default": {"type": "foo"}}
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        assert project_config.envs == {"default": {"type": "foo"}}

    def test_basic(self, isolation):
        env_config = {"foo": {"option": True}}
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        assert project_config.envs == {"default": {"type": "virtual"}, "foo": {"option": True, "type": "virtual"}}

    def test_basic_override(self, isolation):
        env_config = {"foo": {"type": "baz"}}
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        assert project_config.envs == {"default": {"type": "virtual"}, "foo": {"type": "baz"}}

    def test_multiple_inheritance(self, isolation):
        env_config = {
            "foo": {"option1": "foo"},
            "bar": {"template": "foo", "option2": "bar"},
            "baz": {"template": "bar", "option3": "baz"},
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        assert project_config.envs == {
            "default": {"type": "virtual"},
            "foo": {"type": "virtual", "option1": "foo"},
            "bar": {"type": "virtual", "option1": "foo", "option2": "bar"},
            "baz": {"type": "virtual", "option1": "foo", "option2": "bar", "option3": "baz"},
        }

    def test_circular_inheritance(self, isolation):
        with pytest.raises(
            ValueError, match="Circular inheritance detected for field `tool.hatch.envs.*.template`: foo -> bar -> foo"
        ):
            _ = ProjectConfig(
                isolation, {"envs": {"foo": {"template": "bar"}, "bar": {"template": "foo"}}}, PluginManager()
            ).envs

    def test_scripts_inheritance(self, isolation):
        env_config = {
            "default": {"scripts": {"cmd1": "bar", "cmd2": "baz"}},
            "foo": {"scripts": {"cmd1": "foo"}},
            "bar": {"template": "foo", "scripts": {"cmd3": "bar"}},
            "baz": {},
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        assert project_config.envs == {
            "default": {"type": "virtual", "scripts": {"cmd1": "bar", "cmd2": "baz"}},
            "foo": {"type": "virtual", "scripts": {"cmd1": "foo", "cmd2": "baz"}},
            "bar": {"type": "virtual", "scripts": {"cmd1": "foo", "cmd2": "baz", "cmd3": "bar"}},
            "baz": {"type": "virtual", "scripts": {"cmd1": "bar", "cmd2": "baz"}},
        }

    def test_self_referential(self, isolation):
        env_config = {"default": {"option1": "foo"}, "bar": {"template": "bar"}}
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        assert project_config.envs == {
            "default": {"type": "virtual", "option1": "foo"},
            "bar": {"type": "virtual"},
        }

    def test_detached(self, isolation):
        env_config = {"default": {"option1": "foo"}, "bar": {"detached": True}}
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        assert project_config.envs == {
            "default": {"type": "virtual", "option1": "foo"},
            "bar": {"type": "virtual", "skip-install": True},
        }

    def test_matrices_not_array(self, isolation):
        with pytest.raises(TypeError, match="Field `tool.hatch.envs.foo.matrix` must be an array"):
            _ = ProjectConfig(isolation, {"envs": {"foo": {"matrix": 9000}}}, PluginManager()).envs

    def test_matrix_not_table(self, isolation):
        with pytest.raises(TypeError, match="Entry #1 in field `tool.hatch.envs.foo.matrix` must be a table"):
            _ = ProjectConfig(isolation, {"envs": {"foo": {"matrix": [9000]}}}, PluginManager()).envs

    def test_matrix_empty(self, isolation):
        with pytest.raises(ValueError, match="Matrix #1 in field `tool.hatch.envs.foo.matrix` cannot be empty"):
            _ = ProjectConfig(isolation, {"envs": {"foo": {"matrix": [{}]}}}, PluginManager()).envs

    def test_matrix_variable_empty_string(self, isolation):
        with pytest.raises(
            ValueError, match="Variable #1 in matrix #1 in field `tool.hatch.envs.foo.matrix` cannot be an empty string"
        ):
            _ = ProjectConfig(isolation, {"envs": {"foo": {"matrix": [{"": []}]}}}, PluginManager()).envs

    def test_matrix_variable_not_array(self, isolation):
        with pytest.raises(
            TypeError, match="Variable `bar` in matrix #1 in field `tool.hatch.envs.foo.matrix` must be an array"
        ):
            _ = ProjectConfig(isolation, {"envs": {"foo": {"matrix": [{"bar": 9000}]}}}, PluginManager()).envs

    def test_matrix_variable_array_empty(self, isolation):
        with pytest.raises(
            ValueError, match="Variable `bar` in matrix #1 in field `tool.hatch.envs.foo.matrix` cannot be empty"
        ):
            _ = ProjectConfig(isolation, {"envs": {"foo": {"matrix": [{"bar": []}]}}}, PluginManager()).envs

    def test_matrix_variable_entry_not_string(self, isolation):
        with pytest.raises(
            TypeError,
            match="Value #1 of variable `bar` in matrix #1 in field `tool.hatch.envs.foo.matrix` must be a string",
        ):
            _ = ProjectConfig(isolation, {"envs": {"foo": {"matrix": [{"bar": [9000]}]}}}, PluginManager()).envs

    def test_matrix_variable_entry_empty_string(self, isolation):
        with pytest.raises(
            ValueError,
            match=(
                "Value #1 of variable `bar` in matrix #1 in field `tool.hatch.envs.foo.matrix` "
                "cannot be an empty string"
            ),
        ):
            _ = ProjectConfig(isolation, {"envs": {"foo": {"matrix": [{"bar": [""]}]}}}, PluginManager()).envs

    def test_matrix_variable_entry_duplicate(self, isolation):
        with pytest.raises(
            ValueError,
            match="Value #2 of variable `bar` in matrix #1 in field `tool.hatch.envs.foo.matrix` is a duplicate",
        ):
            _ = ProjectConfig(isolation, {"envs": {"foo": {"matrix": [{"bar": ["1", "1"]}]}}}, PluginManager()).envs

    def test_matrix_multiple_python_variables(self, isolation):
        with pytest.raises(
            ValueError,
            match="Matrix #1 in field `tool.hatch.envs.foo.matrix` cannot contain both `py` and `python` variables",
        ):
            _ = ProjectConfig(
                isolation,
                {"envs": {"foo": {"matrix": [{"py": ["39", "310"], "python": ["39", "311"]}]}}},
                PluginManager(),
            ).envs

    def test_matrix_name_format_not_string(self, isolation):
        with pytest.raises(TypeError, match="Field `tool.hatch.envs.foo.matrix-name-format` must be a string"):
            _ = ProjectConfig(isolation, {"envs": {"foo": {"matrix-name-format": 9000}}}, PluginManager()).envs

    def test_matrix_name_format_invalid(self, isolation):
        with pytest.raises(
            ValueError,
            match="Field `tool.hatch.envs.foo.matrix-name-format` must contain at least the `{value}` placeholder",
        ):
            _ = ProjectConfig(isolation, {"envs": {"foo": {"matrix-name-format": "bar"}}}, PluginManager()).envs

    def test_overrides_not_table(self, isolation):
        with pytest.raises(TypeError, match="Field `tool.hatch.envs.foo.overrides` must be a table"):
            _ = ProjectConfig(isolation, {"envs": {"foo": {"overrides": 9000}}}, PluginManager()).envs

    def test_overrides_platform_not_table(self, isolation):
        with pytest.raises(TypeError, match="Field `tool.hatch.envs.foo.overrides.platform` must be a table"):
            _ = ProjectConfig(isolation, {"envs": {"foo": {"overrides": {"platform": 9000}}}}, PluginManager()).envs

    def test_overrides_env_not_table(self, isolation):
        with pytest.raises(TypeError, match="Field `tool.hatch.envs.foo.overrides.env` must be a table"):
            _ = ProjectConfig(isolation, {"envs": {"foo": {"overrides": {"env": 9000}}}}, PluginManager()).envs

    def test_overrides_matrix_not_table(self, isolation):
        with pytest.raises(TypeError, match="Field `tool.hatch.envs.foo.overrides.matrix` must be a table"):
            _ = ProjectConfig(
                isolation,
                {"envs": {"foo": {"matrix": [{"version": ["9000"]}], "overrides": {"matrix": 9000}}}},
                PluginManager(),
            ).envs

    def test_overrides_name_not_table(self, isolation):
        with pytest.raises(TypeError, match="Field `tool.hatch.envs.foo.overrides.name` must be a table"):
            _ = ProjectConfig(
                isolation,
                {"envs": {"foo": {"matrix": [{"version": ["9000"]}], "overrides": {"name": 9000}}}},
                PluginManager(),
            ).envs

    def test_overrides_platform_entry_not_table(self, isolation):
        with pytest.raises(TypeError, match="Field `tool.hatch.envs.foo.overrides.platform.bar` must be a table"):
            _ = ProjectConfig(
                isolation, {"envs": {"foo": {"overrides": {"platform": {"bar": 9000}}}}}, PluginManager()
            ).envs

    def test_overrides_env_entry_not_table(self, isolation):
        with pytest.raises(TypeError, match="Field `tool.hatch.envs.foo.overrides.env.bar` must be a table"):
            _ = ProjectConfig(isolation, {"envs": {"foo": {"overrides": {"env": {"bar": 9000}}}}}, PluginManager()).envs

    def test_overrides_matrix_entry_not_table(self, isolation):
        with pytest.raises(TypeError, match="Field `tool.hatch.envs.foo.overrides.matrix.bar` must be a table"):
            _ = ProjectConfig(
                isolation,
                {"envs": {"foo": {"matrix": [{"version": ["9000"]}], "overrides": {"matrix": {"bar": 9000}}}}},
                PluginManager(),
            ).envs

    def test_overrides_name_entry_not_table(self, isolation):
        with pytest.raises(TypeError, match="Field `tool.hatch.envs.foo.overrides.name.bar` must be a table"):
            _ = ProjectConfig(
                isolation,
                {"envs": {"foo": {"matrix": [{"version": ["9000"]}], "overrides": {"name": {"bar": 9000}}}}},
                PluginManager(),
            ).envs

    def test_matrix_simple_no_python(self, isolation):
        env_config = {"foo": {"option": True, "matrix": [{"version": ["9000", "3.14"]}]}}
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", "option": True},
            "foo.3.14": {"type": "virtual", "option": True},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    def test_matrix_simple_no_python_custom_name_format(self, isolation):
        env_config = {
            "foo": {
                "option": True,
                "matrix-name-format": "{variable}_{value}",
                "matrix": [{"version": ["9000", "3.14"]}],
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.version_9000": {"type": "virtual", "option": True},
            "foo.version_3.14": {"type": "virtual", "option": True},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("indicator", ["py", "python"])
    def test_matrix_simple_only_python(self, isolation, indicator):
        env_config = {"foo": {"option": True, "matrix": [{indicator: ["39", "310"]}]}}
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.py39": {"type": "virtual", "option": True, "python": "39"},
            "foo.py310": {"type": "virtual", "option": True, "python": "310"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("indicator", ["py", "python"])
    def test_matrix_simple(self, isolation, indicator):
        env_config = {"foo": {"option": True, "matrix": [{"version": ["9000", "3.14"], indicator: ["39", "310"]}]}}
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.py39-9000": {"type": "virtual", "option": True, "python": "39"},
            "foo.py39-3.14": {"type": "virtual", "option": True, "python": "39"},
            "foo.py310-9000": {"type": "virtual", "option": True, "python": "310"},
            "foo.py310-3.14": {"type": "virtual", "option": True, "python": "310"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("indicator", ["py", "python"])
    def test_matrix_simple_custom_name_format(self, isolation, indicator):
        env_config = {
            "foo": {
                "option": True,
                "matrix-name-format": "{variable}_{value}",
                "matrix": [{"version": ["9000", "3.14"], indicator: ["39", "310"]}],
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.py39-version_9000": {"type": "virtual", "option": True, "python": "39"},
            "foo.py39-version_3.14": {"type": "virtual", "option": True, "python": "39"},
            "foo.py310-version_9000": {"type": "virtual", "option": True, "python": "310"},
            "foo.py310-version_3.14": {"type": "virtual", "option": True, "python": "310"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    def test_matrix_multiple_non_python(self, isolation):
        env_config = {
            "foo": {
                "option": True,
                "matrix": [{"version": ["9000", "3.14"], "py": ["39", "310"], "foo": ["baz", "bar"]}],
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.py39-9000-baz": {"type": "virtual", "option": True, "python": "39"},
            "foo.py39-9000-bar": {"type": "virtual", "option": True, "python": "39"},
            "foo.py39-3.14-baz": {"type": "virtual", "option": True, "python": "39"},
            "foo.py39-3.14-bar": {"type": "virtual", "option": True, "python": "39"},
            "foo.py310-9000-baz": {"type": "virtual", "option": True, "python": "310"},
            "foo.py310-9000-bar": {"type": "virtual", "option": True, "python": "310"},
            "foo.py310-3.14-baz": {"type": "virtual", "option": True, "python": "310"},
            "foo.py310-3.14-bar": {"type": "virtual", "option": True, "python": "310"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    def test_matrix_series(self, isolation):
        env_config = {
            "foo": {
                "option": True,
                "matrix": [
                    {"version": ["9000", "3.14"], "py": ["39", "310"], "foo": ["baz", "bar"]},
                    {"version": ["9000"], "py": ["310"], "baz": ["foo", "test"], "bar": ["foobar"]},
                ],
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.py39-9000-baz": {"type": "virtual", "option": True, "python": "39"},
            "foo.py39-9000-bar": {"type": "virtual", "option": True, "python": "39"},
            "foo.py39-3.14-baz": {"type": "virtual", "option": True, "python": "39"},
            "foo.py39-3.14-bar": {"type": "virtual", "option": True, "python": "39"},
            "foo.py310-9000-baz": {"type": "virtual", "option": True, "python": "310"},
            "foo.py310-9000-bar": {"type": "virtual", "option": True, "python": "310"},
            "foo.py310-3.14-baz": {"type": "virtual", "option": True, "python": "310"},
            "foo.py310-3.14-bar": {"type": "virtual", "option": True, "python": "310"},
            "foo.py310-9000-foo-foobar": {"type": "virtual", "option": True, "python": "310"},
            "foo.py310-9000-test-foobar": {"type": "virtual", "option": True, "python": "310"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    def test_matrices_not_inherited(self, isolation):
        env_config = {
            "foo": {"option1": True, "matrix": [{"py": ["39"]}]},
            "bar": {"template": "foo", "option2": False},
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.py39": {"type": "virtual", "option1": True, "python": "39"},
            "bar": {"type": "virtual", "option1": True, "option2": False},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    def test_matrix_default_naming(self, isolation):
        env_config = {"default": {"option": True, "matrix": [{"version": ["9000", "3.14"]}]}}
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "9000": {"type": "virtual", "option": True},
            "3.14": {"type": "virtual", "option": True},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["default"] == construct_matrix_data("default", env_config)

    def test_matrix_pypy_naming(self, isolation):
        env_config = {"foo": {"option": True, "matrix": [{"py": ["python3.9", "pypy3"]}]}}
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.python3.9": {"type": "virtual", "option": True, "python": "python3.9"},
            "foo.pypy3": {"type": "virtual", "option": True, "python": "pypy3"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", MAPPING_OPTIONS)
    def test_overrides_matrix_mapping_invalid_type(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=f"Field `tool.hatch.envs.foo.overrides.matrix.version.{option}` must be a string or an array",
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {"matrix": [{"version": ["9000"]}], "overrides": {"matrix": {"version": {option: 9000}}}}
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", MAPPING_OPTIONS)
    def test_overrides_matrix_mapping_array_entry_invalid_type(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=(
                f"Entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must be a string or an inline table"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: [9000]}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", MAPPING_OPTIONS)
    def test_overrides_matrix_mapping_table_entry_no_key(self, isolation, option):
        with pytest.raises(
            ValueError,
            match=(
                f"Entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must have an option named `key`"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {"matrix": [{"version": ["9000"]}], "overrides": {"matrix": {"version": {option: [{}]}}}}
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", MAPPING_OPTIONS)
    def test_overrides_matrix_mapping_table_entry_key_not_string(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=(
                f"Option `key` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must be a string"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: [{"key": 9000}]}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", MAPPING_OPTIONS)
    def test_overrides_matrix_mapping_table_entry_key_empty_string(self, isolation, option):
        with pytest.raises(
            ValueError,
            match=(
                f"Option `key` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"cannot be an empty string"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: [{"key": ""}]}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", MAPPING_OPTIONS)
    def test_overrides_matrix_mapping_table_entry_value_not_string(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=(
                f"Option `value` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must be a string"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: [{"key": "foo", "value": 9000}]}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", MAPPING_OPTIONS)
    def test_overrides_matrix_mapping_table_entry_if_not_array(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=(
                f"Option `if` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must be an array"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {
                                "matrix": {"version": {option: [{"key": "foo", "value": "bar", "if": 9000}]}}
                            },
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", ARRAY_OPTIONS)
    def test_overrides_matrix_array_invalid_type(self, isolation, option):
        with pytest.raises(
            TypeError, match=f"Field `tool.hatch.envs.foo.overrides.matrix.version.{option}` must be an array"
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {"matrix": [{"version": ["9000"]}], "overrides": {"matrix": {"version": {option: 9000}}}}
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", ARRAY_OPTIONS)
    def test_overrides_matrix_array_table_entry_no_value(self, isolation, option):
        with pytest.raises(
            ValueError,
            match=(
                f"Entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must have an option named `value`"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {"matrix": [{"version": ["9000"]}], "overrides": {"matrix": {"version": {option: [{}]}}}}
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", ARRAY_OPTIONS)
    def test_overrides_matrix_array_table_entry_value_not_string(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=(
                f"Option `value` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must be a string"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: [{"value": 9000}]}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", ARRAY_OPTIONS)
    def test_overrides_matrix_array_table_entry_value_empty_string(self, isolation, option):
        with pytest.raises(
            ValueError,
            match=(
                f"Option `value` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"cannot be an empty string"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: [{"value": ""}]}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", ARRAY_OPTIONS)
    def test_overrides_matrix_array_table_entry_if_not_array(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=(
                f"Option `if` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must be an array"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: [{"value": "foo", "if": 9000}]}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", ARRAY_OPTIONS)
    def test_overrides_matrix_array_entry_invalid_type(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=(
                f"Entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must be a string or an inline table"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: [9000]}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", STRING_OPTIONS)
    def test_overrides_matrix_string_invalid_type(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=(
                f"Field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must be a string, inline table, or an array"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {"matrix": [{"version": ["9000"]}], "overrides": {"matrix": {"version": {option: 9000}}}}
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", STRING_OPTIONS)
    def test_overrides_matrix_string_table_no_value(self, isolation, option):
        with pytest.raises(
            ValueError,
            match=f"Field `tool.hatch.envs.foo.overrides.matrix.version.{option}` must have an option named `value`",
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {"matrix": [{"version": ["9000"]}], "overrides": {"matrix": {"version": {option: {}}}}}
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", STRING_OPTIONS)
    def test_overrides_matrix_string_table_value_not_string(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=f"Option `value` in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` must be a string",
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: {"value": 9000}}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", STRING_OPTIONS)
    def test_overrides_matrix_string_array_entry_invalid_type(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=(
                f"Entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must be a string or an inline table"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: [9000]}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", STRING_OPTIONS)
    def test_overrides_matrix_string_array_table_no_value(self, isolation, option):
        with pytest.raises(
            ValueError,
            match=(
                f"Entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must have an option named `value`"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {"matrix": [{"version": ["9000"]}], "overrides": {"matrix": {"version": {option: [{}]}}}}
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", STRING_OPTIONS)
    def test_overrides_matrix_string_array_table_value_not_string(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=(
                f"Option `value` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must be a string"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: [{"value": 9000}]}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", STRING_OPTIONS)
    def test_overrides_matrix_string_array_table_if_not_array(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=(
                f"Option `if` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must be an array"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: [{"value": "foo", "if": 9000}]}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_invalid_type(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=(
                f"Field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must be a boolean, inline table, or an array"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {"matrix": [{"version": ["9000"]}], "overrides": {"matrix": {"version": {option: 9000}}}}
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_table_no_value(self, isolation, option):
        with pytest.raises(
            ValueError,
            match=f"Field `tool.hatch.envs.foo.overrides.matrix.version.{option}` must have an option named `value`",
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {"matrix": [{"version": ["9000"]}], "overrides": {"matrix": {"version": {option: {}}}}}
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_table_value_not_boolean(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=f"Option `value` in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` must be a boolean",
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: {"value": 9000}}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_array_entry_invalid_type(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=(
                f"Entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must be a boolean or an inline table"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: [9000]}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_array_table_no_value(self, isolation, option):
        with pytest.raises(
            ValueError,
            match=(
                f"Entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must have an option named `value`"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {"matrix": [{"version": ["9000"]}], "overrides": {"matrix": {"version": {option: [{}]}}}}
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_array_table_value_not_boolean(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=(
                f"Option `value` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must be a boolean"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: [{"value": 9000}]}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_array_table_if_not_array(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=(
                f"Option `if` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must be an array"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: [{"value": True, "if": 9000}]}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_array_table_platform_not_array(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=(
                f"Option `platform` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must be an array"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: [{"value": True, "platform": 9000}]}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_array_table_platform_item_not_string(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=(
                f"Item #1 in option `platform` in entry #1 in field "
                f"`tool.hatch.envs.foo.overrides.matrix.version.{option}` must be a string"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: [{"value": True, "platform": [9000]}]}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_array_table_env_not_array(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=(
                f"Option `env` in entry #1 in field `tool.hatch.envs.foo.overrides.matrix.version.{option}` "
                f"must be an array"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: [{"value": True, "env": 9000}]}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_array_table_env_item_not_string(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=(
                f"Item #1 in option `env` in entry #1 in field "
                f"`tool.hatch.envs.foo.overrides.matrix.version.{option}` must be a string"
            ),
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {
                            "matrix": [{"version": ["9000"]}],
                            "overrides": {"matrix": {"version": {option: [{"value": True, "env": [9000]}]}}},
                        }
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", MAPPING_OPTIONS)
    def test_overrides_matrix_mapping_string_with_value(self, isolation, option):
        env_config = {
            "foo": {
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: "FOO=ok"}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: {"FOO": "ok"}},
            "foo.bar": {"type": "virtual"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", MAPPING_OPTIONS)
    def test_overrides_matrix_mapping_string_without_value(self, isolation, option):
        env_config = {
            "foo": {
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: "FOO"}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: {"FOO": "9000"}},
            "foo.bar": {"type": "virtual"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", MAPPING_OPTIONS)
    def test_overrides_matrix_mapping_string_override(self, isolation, option):
        env_config = {
            "foo": {
                option: {"TEST": "baz"},
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: "TEST"}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: {"TEST": "9000"}},
            "foo.bar": {"type": "virtual", option: {"TEST": "baz"}},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", MAPPING_OPTIONS)
    def test_overrides_matrix_mapping_array_string_with_value(self, isolation, option):
        env_config = {
            "foo": {
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: ["FOO=ok"]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: {"FOO": "ok"}},
            "foo.bar": {"type": "virtual"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", MAPPING_OPTIONS)
    def test_overrides_matrix_mapping_array_string_without_value(self, isolation, option):
        env_config = {
            "foo": {
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: ["FOO"]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: {"FOO": "9000"}},
            "foo.bar": {"type": "virtual"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", MAPPING_OPTIONS)
    def test_overrides_matrix_mapping_array_string_override(self, isolation, option):
        env_config = {
            "foo": {
                option: {"TEST": "baz"},
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: ["TEST"]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: {"TEST": "9000"}},
            "foo.bar": {"type": "virtual", option: {"TEST": "baz"}},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", MAPPING_OPTIONS)
    def test_overrides_matrix_mapping_array_table_key_with_value(self, isolation, option):
        env_config = {
            "foo": {
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: [{"key": "FOO", "value": "ok"}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: {"FOO": "ok"}},
            "foo.bar": {"type": "virtual"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", MAPPING_OPTIONS)
    def test_overrides_matrix_mapping_array_table_key_without_value(self, isolation, option):
        env_config = {
            "foo": {
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: [{"key": "FOO"}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: {"FOO": "9000"}},
            "foo.bar": {"type": "virtual"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", MAPPING_OPTIONS)
    def test_overrides_matrix_mapping_array_table_override(self, isolation, option):
        env_config = {
            "foo": {
                option: {"TEST": "baz"},
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: [{"key": "TEST"}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: {"TEST": "9000"}},
            "foo.bar": {"type": "virtual", option: {"TEST": "baz"}},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", MAPPING_OPTIONS)
    def test_overrides_matrix_mapping_array_table_conditional(self, isolation, option):
        env_config = {
            "foo": {
                option: {"TEST": "baz"},
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: [{"key": "TEST", "if": ["42"]}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: {"TEST": "baz"}},
            "foo.42": {"type": "virtual", option: {"TEST": "42"}},
            "foo.bar": {"type": "virtual", option: {"TEST": "baz"}},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", MAPPING_OPTIONS)
    def test_overrides_matrix_mapping_overwrite(self, isolation, option):
        env_config = {
            "foo": {
                option: {"TEST": "baz"},
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {f"set-{option}": ["FOO=bar", {"key": "BAZ"}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: {"FOO": "bar", "BAZ": "9000"}},
            "foo.bar": {"type": "virtual", option: {"TEST": "baz"}},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", ARRAY_OPTIONS)
    def test_overrides_matrix_array_string(self, isolation, option):
        env_config = {
            "foo": {
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: ["run foo"]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: ["run foo"]},
            "foo.bar": {"type": "virtual"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", ARRAY_OPTIONS)
    def test_overrides_matrix_array_string_existing_append(self, isolation, option):
        env_config = {
            "foo": {
                option: ["run baz"],
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: ["run foo"]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: ["run baz", "run foo"]},
            "foo.bar": {"type": "virtual", option: ["run baz"]},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", ARRAY_OPTIONS)
    def test_overrides_matrix_array_table(self, isolation, option):
        env_config = {
            "foo": {
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: [{"value": "run foo"}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: ["run foo"]},
            "foo.bar": {"type": "virtual"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", ARRAY_OPTIONS)
    def test_overrides_matrix_array_table_existing_append(self, isolation, option):
        env_config = {
            "foo": {
                option: ["run baz"],
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: [{"value": "run foo"}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: ["run baz", "run foo"]},
            "foo.bar": {"type": "virtual", option: ["run baz"]},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", ARRAY_OPTIONS)
    def test_overrides_matrix_array_table_conditional(self, isolation, option):
        env_config = {
            "foo": {
                option: ["run baz"],
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: [{"value": "run foo", "if": ["42"]}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: ["run baz"]},
            "foo.42": {"type": "virtual", option: ["run baz", "run foo"]},
            "foo.bar": {"type": "virtual", option: ["run baz"]},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", ARRAY_OPTIONS)
    def test_overrides_matrix_array_table_conditional_with_platform(self, isolation, option, current_platform):
        env_config = {
            "foo": {
                option: ["run baz"],
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {
                    "matrix": {
                        "version": {option: [{"value": "run foo", "if": ["42"], "platform": [current_platform]}]}
                    },
                },
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: ["run baz"]},
            "foo.42": {"type": "virtual", option: ["run baz", "run foo"]},
            "foo.bar": {"type": "virtual", option: ["run baz"]},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", ARRAY_OPTIONS)
    def test_overrides_matrix_array_table_conditional_with_wrong_platform(self, isolation, option):
        env_config = {
            "foo": {
                option: ["run baz"],
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {
                    "matrix": {"version": {option: [{"value": "run foo", "if": ["42"], "platform": ["bar"]}]}},
                },
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: ["run baz"]},
            "foo.42": {"type": "virtual", option: ["run baz"]},
            "foo.bar": {"type": "virtual", option: ["run baz"]},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", ARRAY_OPTIONS)
    def test_overrides_matrix_array_table_conditional_with_env_var_match(self, isolation, option):
        env_var = "OVERRIDES_ENV_FOO"
        env_config = {
            "foo": {
                option: ["run baz"],
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {
                    "matrix": {"version": {option: [{"value": "run foo", "if": ["42"], "env": [f"{env_var}=bar"]}]}}
                },
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: ["run baz"]},
            "foo.42": {"type": "virtual", option: ["run baz", "run foo"]},
            "foo.bar": {"type": "virtual", option: ["run baz"]},
        }

        with EnvVars({env_var: "bar"}):
            assert project_config.envs == expected_envs
            assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", ARRAY_OPTIONS)
    def test_overrides_matrix_array_table_conditional_with_env_var_match_empty_string(self, isolation, option):
        env_var = "OVERRIDES_ENV_FOO"
        env_config = {
            "foo": {
                option: ["run baz"],
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {
                    "matrix": {"version": {option: [{"value": "run foo", "if": ["42"], "env": [f"{env_var}="]}]}}
                },
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: ["run baz"]},
            "foo.42": {"type": "virtual", option: ["run baz", "run foo"]},
            "foo.bar": {"type": "virtual", option: ["run baz"]},
        }

        with EnvVars({env_var: ""}):
            assert project_config.envs == expected_envs
            assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", ARRAY_OPTIONS)
    def test_overrides_matrix_array_table_conditional_with_env_var_present(self, isolation, option):
        env_var = "OVERRIDES_ENV_FOO"
        env_config = {
            "foo": {
                option: ["run baz"],
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: [{"value": "run foo", "if": ["42"], "env": [env_var]}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: ["run baz"]},
            "foo.42": {"type": "virtual", option: ["run baz", "run foo"]},
            "foo.bar": {"type": "virtual", option: ["run baz"]},
        }

        with EnvVars({env_var: "any"}):
            assert project_config.envs == expected_envs
            assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", ARRAY_OPTIONS)
    def test_overrides_matrix_array_table_conditional_with_env_var_no_match(self, isolation, option):
        env_var = "OVERRIDES_ENV_FOO"
        env_config = {
            "foo": {
                option: ["run baz"],
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {
                    "matrix": {"version": {option: [{"value": "run foo", "if": ["42"], "env": [f"{env_var}=bar"]}]}}
                },
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: ["run baz"]},
            "foo.42": {"type": "virtual", option: ["run baz"]},
            "foo.bar": {"type": "virtual", option: ["run baz"]},
        }

        with EnvVars({env_var: "baz"}):
            assert project_config.envs == expected_envs
            assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", ARRAY_OPTIONS)
    def test_overrides_matrix_array_table_conditional_with_env_var_missing(self, isolation, option):
        env_var = "OVERRIDES_ENV_FOO"
        env_config = {
            "foo": {
                option: ["run baz"],
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {
                    "matrix": {"version": {option: [{"value": "run foo", "if": ["42"], "env": [f"{env_var}=bar"]}]}}
                },
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: ["run baz"]},
            "foo.42": {"type": "virtual", option: ["run baz"]},
            "foo.bar": {"type": "virtual", option: ["run baz"]},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    def test_overrides_matrix_set_with_no_type_information(self, isolation):
        env_var = "OVERRIDES_ENV_FOO"
        env_config = {
            "foo": {
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {
                    "matrix": {"version": {"bar": {"value": ["baz"], "if": ["42"], "env": [f"{env_var}=bar"]}}}
                },
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual"},
            "foo.42": {"type": "virtual", "bar": ["baz"]},
            "foo.bar": {"type": "virtual"},
        }

        with EnvVars({env_var: "bar"}):
            assert project_config.envs == expected_envs
            assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    def test_overrides_matrix_set_with_no_type_information_not_table(self, isolation):
        project_config = ProjectConfig(
            isolation,
            {
                "envs": {
                    "foo": {
                        "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                        "overrides": {"matrix": {"version": {"bar": 9000}}},
                    }
                }
            },
            PluginManager(),
        )
        _ = project_config.envs

        with pytest.raises(
            ValueError,
            match=(
                "Untyped option `tool.hatch.envs.foo.9000.overrides.matrix.version.bar` "
                "must be defined as a table with a `value` key"
            ),
        ):
            project_config.finalize_env_overrides({})

    @pytest.mark.parametrize("option", ARRAY_OPTIONS)
    def test_overrides_matrix_array_overwrite(self, isolation, option):
        env_config = {
            "foo": {
                option: ["run baz"],
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {f"set-{option}": ["run foo", {"value": "run bar"}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: ["run foo", "run bar"]},
            "foo.bar": {"type": "virtual", option: ["run baz"]},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", STRING_OPTIONS)
    def test_overrides_matrix_string_string_create(self, isolation, option):
        env_config = {
            "foo": {
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: "baz"}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: "baz"},
            "foo.bar": {"type": "virtual"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", STRING_OPTIONS)
    def test_overrides_matrix_string_string_overwrite(self, isolation, option):
        env_config = {
            "foo": {
                option: "test",
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: "baz"}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: "baz"},
            "foo.bar": {"type": "virtual", option: "test"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", STRING_OPTIONS)
    def test_overrides_matrix_string_table_create(self, isolation, option):
        env_config = {
            "foo": {
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: {"value": "baz"}}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: "baz"},
            "foo.bar": {"type": "virtual"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", STRING_OPTIONS)
    def test_overrides_matrix_string_table_override(self, isolation, option):
        env_config = {
            "foo": {
                option: "test",
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: {"value": "baz"}}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: "baz"},
            "foo.bar": {"type": "virtual", option: "test"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", STRING_OPTIONS)
    def test_overrides_matrix_string_table_conditional(self, isolation, option):
        env_config = {
            "foo": {
                option: "test",
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: {"value": "baz", "if": ["42"]}}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: "test"},
            "foo.42": {"type": "virtual", option: "baz"},
            "foo.bar": {"type": "virtual", option: "test"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", STRING_OPTIONS)
    def test_overrides_matrix_string_array_table_create(self, isolation, option):
        env_config = {
            "foo": {
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: [{"value": "baz"}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: "baz"},
            "foo.bar": {"type": "virtual"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", STRING_OPTIONS)
    def test_overrides_matrix_string_array_table_override(self, isolation, option):
        env_config = {
            "foo": {
                option: "test",
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: [{"value": "baz"}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: "baz"},
            "foo.bar": {"type": "virtual", option: "test"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", STRING_OPTIONS)
    def test_overrides_matrix_string_array_table_conditional(self, isolation, option):
        env_config = {
            "foo": {
                option: "test",
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: [{"value": "baz", "if": ["42"]}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: "test"},
            "foo.42": {"type": "virtual", option: "baz"},
            "foo.bar": {"type": "virtual", option: "test"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", STRING_OPTIONS)
    def test_overrides_matrix_string_array_table_conditional_eager_string(self, isolation, option):
        env_config = {
            "foo": {
                option: "test",
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: ["baz", {"value": "foo", "if": ["42"]}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: "baz"},
            "foo.42": {"type": "virtual", option: "baz"},
            "foo.bar": {"type": "virtual", option: "test"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", STRING_OPTIONS)
    def test_overrides_matrix_string_array_table_conditional_eager_table(self, isolation, option):
        env_config = {
            "foo": {
                option: "test",
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: [{"value": "baz", "if": ["42"]}, "foo"]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: "foo"},
            "foo.42": {"type": "virtual", option: "baz"},
            "foo.bar": {"type": "virtual", option: "test"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_boolean_create(self, isolation, option):
        env_config = {
            "foo": {
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: True}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: True},
            "foo.bar": {"type": "virtual"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_boolean_overwrite(self, isolation, option):
        env_config = {
            "foo": {
                option: False,
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: True}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: True},
            "foo.bar": {"type": "virtual", option: False},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_table_create(self, isolation, option):
        env_config = {
            "foo": {
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: {"value": True}}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: True},
            "foo.bar": {"type": "virtual"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_table_override(self, isolation, option):
        env_config = {
            "foo": {
                option: False,
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: {"value": True}}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: True},
            "foo.bar": {"type": "virtual", option: False},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_table_conditional(self, isolation, option):
        env_config = {
            "foo": {
                option: False,
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: {"value": True, "if": ["42"]}}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: False},
            "foo.42": {"type": "virtual", option: True},
            "foo.bar": {"type": "virtual", option: False},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_array_table_create(self, isolation, option):
        env_config = {
            "foo": {
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: [{"value": True}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: True},
            "foo.bar": {"type": "virtual"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_array_table_override(self, isolation, option):
        env_config = {
            "foo": {
                option: False,
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: [{"value": True}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: True},
            "foo.bar": {"type": "virtual", option: False},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_array_table_conditional(self, isolation, option):
        env_config = {
            "foo": {
                option: False,
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: [{"value": True, "if": ["42"]}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: False},
            "foo.42": {"type": "virtual", option: True},
            "foo.bar": {"type": "virtual", option: False},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_array_table_conditional_eager_boolean(self, isolation, option):
        env_config = {
            "foo": {
                option: False,
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: [True, {"value": False, "if": ["42"]}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: True},
            "foo.42": {"type": "virtual", option: True},
            "foo.bar": {"type": "virtual", option: False},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", BOOLEAN_OPTIONS)
    def test_overrides_matrix_boolean_array_table_conditional_eager_table(self, isolation, option):
        env_config = {
            "foo": {
                option: False,
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: [{"value": True, "if": ["42"]}, False]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: False},
            "foo.42": {"type": "virtual", option: True},
            "foo.bar": {"type": "virtual", option: False},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    # We assert type coverage using matrix variable overrides, for the others just test one type
    def test_overrides_platform_boolean_boolean_create(self, isolation, current_platform):
        env_config = {
            "foo": {
                "overrides": {"platform": {"bar": {"dependencies": ["baz"]}, current_platform: {"skip-install": True}}}
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo": {"type": "virtual", "skip-install": True},
        }

        assert project_config.envs == expected_envs

    def test_overrides_platform_boolean_boolean_overwrite(self, isolation, current_platform):
        env_config = {
            "foo": {
                "skip-install": True,
                "overrides": {
                    "platform": {"bar": {"dependencies": ["baz"]}, current_platform: {"skip-install": False}}
                },
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo": {"type": "virtual", "skip-install": False},
        }

        assert project_config.envs == expected_envs

    def test_overrides_platform_boolean_table_create(self, isolation, current_platform):
        env_config = {
            "foo": {
                "overrides": {
                    "platform": {
                        "bar": {"dependencies": ["baz"]},
                        current_platform: {"skip-install": [{"value": True}]},
                    }
                }
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo": {"type": "virtual", "skip-install": True},
        }

        assert project_config.envs == expected_envs

    def test_overrides_platform_boolean_table_overwrite(self, isolation, current_platform):
        env_config = {
            "foo": {
                "skip-install": True,
                "overrides": {
                    "platform": {
                        "bar": {"dependencies": ["baz"]},
                        current_platform: {"skip-install": [{"value": False}]},
                    }
                },
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo": {"type": "virtual", "skip-install": False},
        }

        assert project_config.envs == expected_envs

    def test_overrides_env_boolean_boolean_create(self, isolation):
        env_var_exists = "OVERRIDES_ENV_FOO"
        env_var_missing = "OVERRIDES_ENV_BAR"
        env_config = {
            "foo": {
                "overrides": {
                    "env": {env_var_missing: {"dependencies": ["baz"]}, env_var_exists: {"skip-install": True}}
                }
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo": {"type": "virtual", "skip-install": True},
        }

        with EnvVars({env_var_exists: "any"}):
            assert project_config.envs == expected_envs

    def test_overrides_env_boolean_boolean_overwrite(self, isolation):
        env_var_exists = "OVERRIDES_ENV_FOO"
        env_var_missing = "OVERRIDES_ENV_BAR"
        env_config = {
            "foo": {
                "skip-install": True,
                "overrides": {
                    "env": {env_var_missing: {"dependencies": ["baz"]}, env_var_exists: {"skip-install": False}}
                },
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo": {"type": "virtual", "skip-install": False},
        }

        with EnvVars({env_var_exists: "any"}):
            assert project_config.envs == expected_envs

    def test_overrides_env_boolean_table_create(self, isolation):
        env_var_exists = "OVERRIDES_ENV_FOO"
        env_var_missing = "OVERRIDES_ENV_BAR"
        env_config = {
            "foo": {
                "overrides": {
                    "env": {
                        env_var_missing: {"dependencies": ["baz"]},
                        env_var_exists: {"skip-install": [{"value": True}]},
                    }
                }
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo": {"type": "virtual", "skip-install": True},
        }

        with EnvVars({env_var_exists: "any"}):
            assert project_config.envs == expected_envs

    def test_overrides_env_boolean_table_overwrite(self, isolation):
        env_var_exists = "OVERRIDES_ENV_FOO"
        env_var_missing = "OVERRIDES_ENV_BAR"
        env_config = {
            "foo": {
                "skip-install": True,
                "overrides": {
                    "env": {
                        env_var_missing: {"dependencies": ["baz"]},
                        env_var_exists: {"skip-install": [{"value": False}]},
                    }
                },
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo": {"type": "virtual", "skip-install": False},
        }

        with EnvVars({env_var_exists: "any"}):
            assert project_config.envs == expected_envs

    def test_overrides_env_boolean_conditional(self, isolation):
        env_var_exists = "OVERRIDES_ENV_FOO"
        env_var_missing = "OVERRIDES_ENV_BAR"
        env_config = {
            "foo": {
                "overrides": {
                    "env": {
                        env_var_missing: {"dependencies": ["baz"]},
                        env_var_exists: {"skip-install": [{"value": True, "if": ["foo"]}]},
                    }
                }
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo": {"type": "virtual", "skip-install": True},
        }

        with EnvVars({env_var_exists: "foo"}):
            assert project_config.envs == expected_envs

    def test_overrides_name_boolean_boolean_create(self, isolation):
        env_config = {
            "foo": {
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"name": {"bar$": {"skip-install": True}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual"},
            "foo.bar": {"type": "virtual", "skip-install": True},
        }

        assert project_config.envs == expected_envs

    def test_overrides_name_boolean_boolean_overwrite(self, isolation):
        env_config = {
            "foo": {
                "skip-install": True,
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"name": {"bar$": {"skip-install": False}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", "skip-install": True},
            "foo.bar": {"type": "virtual", "skip-install": False},
        }

        assert project_config.envs == expected_envs

    def test_overrides_name_boolean_table_create(self, isolation):
        env_config = {
            "foo": {
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"name": {"bar$": {"skip-install": [{"value": True}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual"},
            "foo.bar": {"type": "virtual", "skip-install": True},
        }

        assert project_config.envs == expected_envs

    def test_overrides_name_boolean_table_overwrite(self, isolation):
        env_config = {
            "foo": {
                "skip-install": True,
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"name": {"bar$": {"skip-install": [{"value": False}]}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", "skip-install": True},
            "foo.bar": {"type": "virtual", "skip-install": False},
        }

        assert project_config.envs == expected_envs

    # Tests for source precedence
    def test_overrides_name_precedence_over_matrix(self, isolation):
        env_config = {
            "foo": {
                "skip-install": False,
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {
                    "name": {"42$": {"skip-install": False}},
                    "matrix": {"version": {"skip-install": [{"value": True, "if": ["42"]}]}},
                },
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", "skip-install": False},
            "foo.42": {"type": "virtual", "skip-install": False},
            "foo.bar": {"type": "virtual", "skip-install": False},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config, {"skip-install": False})

    def test_overrides_matrix_precedence_over_platform(self, isolation, current_platform):
        env_config = {
            "foo": {
                "skip-install": False,
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {
                    "platform": {current_platform: {"skip-install": True}},
                    "matrix": {"version": {"skip-install": [{"value": False, "if": ["42"]}]}},
                },
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", "skip-install": True},
            "foo.42": {"type": "virtual", "skip-install": False},
            "foo.bar": {"type": "virtual", "skip-install": True},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config, {"skip-install": True})

    def test_overrides_matrix_precedence_over_env(self, isolation):
        env_var = "OVERRIDES_ENV_FOO"
        env_config = {
            "foo": {
                "skip-install": False,
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {
                    "env": {env_var: {"skip-install": True}},
                    "matrix": {"version": {"skip-install": [{"value": False, "if": ["42"]}]}},
                },
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", "skip-install": True},
            "foo.42": {"type": "virtual", "skip-install": False},
            "foo.bar": {"type": "virtual", "skip-install": True},
        }

        with EnvVars({env_var: "any"}):
            assert project_config.envs == expected_envs
            assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config, {"skip-install": True})

    def test_overrides_env_precedence_over_platform(self, isolation, current_platform):
        env_var = "OVERRIDES_ENV_FOO"
        env_config = {
            "foo": {
                "overrides": {
                    "platform": {current_platform: {"skip-install": True}},
                    "env": {env_var: {"skip-install": [{"value": False, "if": ["foo"]}]}},
                },
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo": {"type": "virtual", "skip-install": False},
        }

        with EnvVars({env_var: "foo"}):
            assert project_config.envs == expected_envs

    # Test for options defined by environment plugins
    def test_overrides_for_environment_plugins(self, isolation, current_platform):
        env_var = "OVERRIDES_ENV_FOO"
        env_config = {
            "foo": {
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {
                    "platform": {current_platform: {"foo": True}},
                    "env": {env_var: {"bar": [{"value": "foobar", "if": ["foo"]}]}},
                    "matrix": {"version": {"baz": "BAR=ok"}},
                },
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual"},
            "foo.bar": {"type": "virtual"},
        }

        with EnvVars({env_var: "foo"}):
            assert project_config.envs == expected_envs
            assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

        project_config.finalize_env_overrides({"foo": bool, "bar": str, "baz": dict})

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", "foo": True, "bar": "foobar", "baz": {"BAR": "ok"}},
            "foo.bar": {"type": "virtual", "foo": True, "bar": "foobar"},
        }

        assert project_config.envs == expected_envs
        assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    # Test environment collectors
    def test_environment_collector_finalize_config(self, helpers, temp_dir):
        file_path = temp_dir / DEFAULT_CUSTOM_SCRIPT
        file_path.write_text(
            helpers.dedent(
                """
                from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface

                class CustomHook(EnvironmentCollectorInterface):
                    def finalize_config(self, config):
                        config['default']['type'] = 'foo'
                """
            )
        )

        env_config = {
            "foo": {
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {"type": {"value": "baz", "if": ["42"]}}}},
            }
        }
        project_config = ProjectConfig(
            temp_dir, {"envs": env_config, "env": {"collectors": {"custom": {}}}}, PluginManager()
        )

        expected_envs = {
            "default": {"type": "foo"},
            "foo.9000": {"type": "foo"},
            "foo.42": {"type": "baz"},
            "foo.bar": {"type": "foo"},
        }

        with temp_dir.as_cwd():
            assert project_config.envs == expected_envs
            assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config, {"type": "foo"})

    def test_environment_collector_finalize_environments(self, helpers, temp_dir):
        file_path = temp_dir / DEFAULT_CUSTOM_SCRIPT
        file_path.write_text(
            helpers.dedent(
                """
                from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface

                class CustomHook(EnvironmentCollectorInterface):
                    def finalize_environments(self, config):
                        config['foo.42']['type'] = 'foo'
                """
            )
        )

        env_config = {
            "foo": {
                "matrix": [{"version": ["9000", "42"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {"type": {"value": "baz", "if": ["42"]}}}},
            }
        }
        project_config = ProjectConfig(
            temp_dir, {"envs": env_config, "env": {"collectors": {"custom": {}}}}, PluginManager()
        )

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual"},
            "foo.42": {"type": "foo"},
            "foo.bar": {"type": "virtual"},
        }

        with temp_dir.as_cwd():
            assert project_config.envs == expected_envs
            assert project_config.matrices["foo"] == construct_matrix_data("foo", env_config)

    @pytest.mark.parametrize("option", WORKSPACE_OPTIONS)
    def test_overrides_matrix_workspace_invalid_type(self, isolation, option):
        with pytest.raises(
            TypeError,
            match=f"Field `tool.hatch.envs.foo.overrides.matrix.version.{option}` must be a table",
        ):
            _ = ProjectConfig(
                isolation,
                {
                    "envs": {
                        "foo": {"matrix": [{"version": ["9000"]}], "overrides": {"matrix": {"version": {option: 9000}}}}
                    }
                },
                PluginManager(),
            ).envs

    @pytest.mark.parametrize("option", WORKSPACE_OPTIONS)
    def test_overrides_matrix_workspace_members_append(self, isolation, option):
        env_config = {
            "foo": {
                option: {"members": ["packages/core"]},
                "matrix": [{"version": ["9000"]}, {"feature": ["bar"]}],
                "overrides": {"matrix": {"version": {option: {"members": ["packages/extra"]}}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: {"members": ["packages/core", "packages/extra"]}},
            "foo.bar": {"type": "virtual", option: {"members": ["packages/core"]}},
        }

        assert project_config.envs == expected_envs

    @pytest.mark.parametrize("option", WORKSPACE_OPTIONS)
    def test_overrides_matrix_workspace_members_conditional(self, isolation, option):
        env_config = {
            "foo": {
                option: {"members": ["packages/core"]},
                "matrix": [{"version": ["9000", "42"]}],
                "overrides": {
                    "matrix": {"version": {option: {"members": [{"value": "packages/special", "if": ["42"]}]}}}
                },
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: {"members": ["packages/core"]}},
            "foo.42": {"type": "virtual", option: {"members": ["packages/core", "packages/special"]}},
        }

        assert project_config.envs == expected_envs

    @pytest.mark.parametrize("option", WORKSPACE_OPTIONS)
    def test_overrides_matrix_workspace_parallel(self, isolation, option):
        env_config = {
            "foo": {
                option: {"members": ["packages/*"], "parallel": True},
                "matrix": [{"version": ["9000", "42"]}],
                "overrides": {"matrix": {"version": {option: {"parallel": {"value": False, "if": ["42"]}}}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: {"members": ["packages/*"], "parallel": True}},
            "foo.42": {"type": "virtual", option: {"members": ["packages/*"], "parallel": False}},
        }

        assert project_config.envs == expected_envs

    @pytest.mark.parametrize("option", WORKSPACE_OPTIONS)
    def test_overrides_matrix_workspace_overwrite(self, isolation, option):
        env_config = {
            "foo": {
                option: {"members": ["packages/core"], "parallel": True},
                "matrix": [{"version": ["9000"]}],
                "overrides": {"matrix": {"version": {f"set-{option}": {"members": ["packages/new"]}}}},
            }
        }
        project_config = ProjectConfig(isolation, {"envs": env_config}, PluginManager())

        expected_envs = {
            "default": {"type": "virtual"},
            "foo.9000": {"type": "virtual", option: {"members": ["packages/new"]}},
        }

        assert project_config.envs == expected_envs


class TestPublish:
    def test_not_table(self, isolation):
        with pytest.raises(TypeError, match="Field `tool.hatch.publish` must be a table"):
            _ = ProjectConfig(isolation, {"publish": 9000}).publish

    def test_config_not_table(self, isolation):
        with pytest.raises(TypeError, match="Field `tool.hatch.publish.foo` must be a table"):
            _ = ProjectConfig(isolation, {"publish": {"foo": 9000}}).publish

    def test_default(self, isolation):
        project_config = ProjectConfig(isolation, {})

        assert project_config.publish == project_config.publish == {}

    def test_defined(self, isolation):
        project_config = ProjectConfig(isolation, {"publish": {"foo": {"bar": "baz"}}})

        assert project_config.publish == {"foo": {"bar": "baz"}}


class TestScripts:
    def test_not_table(self, isolation):
        config = {"scripts": 9000}
        project_config = ProjectConfig(isolation, config)

        with pytest.raises(TypeError, match="Field `tool.hatch.scripts` must be a table"):
            _ = project_config.scripts

    def test_name_contains_spaces(self, isolation):
        config = {"scripts": {"foo bar": []}}
        project_config = ProjectConfig(isolation, config)

        with pytest.raises(
            ValueError, match="Script name `foo bar` in field `tool.hatch.scripts` must not contain spaces"
        ):
            _ = project_config.scripts

    def test_default(self, isolation):
        project_config = ProjectConfig(isolation, {})

        assert project_config.scripts == project_config.scripts == {}

    def test_single_commands(self, isolation):
        config = {"scripts": {"foo": "command1", "bar": "command2"}}
        project_config = ProjectConfig(isolation, config)

        assert project_config.scripts == {"foo": ["command1"], "bar": ["command2"]}

    def test_multiple_commands(self, isolation):
        config = {"scripts": {"foo": "command1", "bar": ["command3", "command2"]}}
        project_config = ProjectConfig(isolation, config)

        assert project_config.scripts == {"foo": ["command1"], "bar": ["command3", "command2"]}

    def test_multiple_commands_not_string(self, isolation):
        config = {"scripts": {"foo": [9000]}}
        project_config = ProjectConfig(isolation, config)

        with pytest.raises(TypeError, match="Command #1 in field `tool.hatch.scripts.foo` must be a string"):
            _ = project_config.scripts

    def test_config_invalid_type(self, isolation):
        config = {"scripts": {"foo": 9000}}
        project_config = ProjectConfig(isolation, config)

        with pytest.raises(TypeError, match="Field `tool.hatch.scripts.foo` must be a string or an array of strings"):
            _ = project_config.scripts

    def test_command_expansion_basic(self, isolation):
        config = {"scripts": {"foo": "command1", "bar": ["command3", "foo"]}}
        project_config = ProjectConfig(isolation, config)

        assert project_config.scripts == {"foo": ["command1"], "bar": ["command3", "command1"]}

    def test_command_expansion_multiple_nested(self, isolation):
        config = {
            "scripts": {
                "foo": "command3",
                "baz": ["command5", "bar", "foo", "command1"],
                "bar": ["command4", "foo", "command2"],
            }
        }
        project_config = ProjectConfig(isolation, config)

        assert project_config.scripts == {
            "foo": ["command3"],
            "baz": ["command5", "command4", "command3", "command2", "command3", "command1"],
            "bar": ["command4", "command3", "command2"],
        }

    def test_command_expansion_multiple_nested_ignore_exit_code(self, isolation):
        config = {
            "scripts": {
                "foo": "command3",
                "baz": ["command5", "- bar", "foo", "command1"],
                "bar": ["command4", "- foo", "command2"],
            }
        }
        project_config = ProjectConfig(isolation, config)

        assert project_config.scripts == {
            "foo": ["command3"],
            "baz": ["command5", "- command4", "- command3", "- command2", "command3", "command1"],
            "bar": ["command4", "- command3", "command2"],
        }

    def test_command_expansion_modification(self, isolation):
        config = {
            "scripts": {
                "foo": "command3",
                "baz": ["command5", "bar world", "foo", "command1"],
                "bar": ["command4", "foo hello", "command2"],
            }
        }
        project_config = ProjectConfig(isolation, config)

        assert project_config.scripts == {
            "foo": ["command3"],
            "baz": ["command5", "command4 world", "command3 hello world", "command2 world", "command3", "command1"],
            "bar": ["command4", "command3 hello", "command2"],
        }

    def test_command_expansion_circular_inheritance(self, isolation):
        config = {"scripts": {"foo": "bar", "bar": "foo"}}
        project_config = ProjectConfig(isolation, config)

        with pytest.raises(
            ValueError, match="Circular expansion detected for field `tool.hatch.scripts`: foo -> bar -> foo"
        ):
            _ = project_config.scripts


class TestBuild:
    def test_not_table(self, isolation):
        config = {"build": 9000}
        project_config = ProjectConfig(isolation, config)

        with pytest.raises(TypeError, match="Field `tool.hatch.build` must be a table"):
            _ = project_config.build

    def test_targets_not_table(self, isolation):
        config = {"build": {"targets": 9000}}
        project_config = ProjectConfig(isolation, config)

        with pytest.raises(TypeError, match="Field `tool.hatch.build.targets` must be a table"):
            _ = project_config.build.target("foo")

    def test_target_not_table(self, isolation):
        config = {"build": {"targets": {"foo": 9000}}}
        project_config = ProjectConfig(isolation, config)

        with pytest.raises(TypeError, match="Field `tool.hatch.build.targets.foo` must be a table"):
            _ = project_config.build.target("foo")

    def test_directory_global_not_table(self, isolation):
        config = {"build": {"directory": 9000}}
        project_config = ProjectConfig(isolation, config)

        with pytest.raises(TypeError, match="Field `tool.hatch.build.directory` must be a string"):
            _ = project_config.build.target("foo").directory

    def test_directory_not_table(self, isolation):
        config = {"build": {"targets": {"foo": {"directory": 9000}}}}
        project_config = ProjectConfig(isolation, config)

        with pytest.raises(TypeError, match="Field `tool.hatch.build.targets.foo.directory` must be a string"):
            _ = project_config.build.target("foo").directory

    def test_directory_default(self, isolation):
        project_config = ProjectConfig(isolation, {})

        assert project_config.build.target("foo").directory == DEFAULT_BUILD_DIRECTORY

    def test_directory_global_correct(self, isolation):
        config = {"build": {"directory": "bar"}}
        project_config = ProjectConfig(isolation, config)

        assert project_config.build.target("foo").directory == "bar"

    def test_directory_target_override(self, isolation):
        config = {"build": {"directory": "bar", "targets": {"foo": {"directory": "baz"}}}}
        project_config = ProjectConfig(isolation, config)

        assert project_config.build.target("foo").directory == "baz"

    def test_dependencies_global_not_array(self, isolation):
        config = {"build": {"dependencies": 9000}}
        project_config = ProjectConfig(isolation, config)

        with pytest.raises(TypeError, match="Field `tool.hatch.build.dependencies` must be an array"):
            _ = project_config.build.target("foo").dependencies

    def test_dependencies_global_entry_not_string(self, isolation):
        config = {"build": {"dependencies": [9000]}}
        project_config = ProjectConfig(isolation, config)

        with pytest.raises(TypeError, match="Dependency #1 in field `tool.hatch.build.dependencies` must be a string"):
            _ = project_config.build.target("foo").dependencies

    def test_dependencies_not_array(self, isolation):
        config = {"build": {"targets": {"foo": {"dependencies": 9000}}}}
        project_config = ProjectConfig(isolation, config)

        with pytest.raises(TypeError, match="Field `tool.hatch.build.targets.foo.dependencies` must be an array"):
            _ = project_config.build.target("foo").dependencies

    def test_dependencies_entry_not_string(self, isolation):
        config = {"build": {"targets": {"foo": {"dependencies": [9000]}}}}
        project_config = ProjectConfig(isolation, config)

        with pytest.raises(
            TypeError, match="Dependency #1 in field `tool.hatch.build.targets.foo.dependencies` must be a string"
        ):
            _ = project_config.build.target("foo").dependencies

    def test_dependencies_target_merge(self, isolation):
        config = {"build": {"dependencies": ["baz"], "targets": {"foo": {"dependencies": ["bar"]}}}}
        project_config = ProjectConfig(isolation, config)

        assert project_config.build.target("foo").dependencies == ["baz", "bar"]

    def test_hooks_global_not_table(self, isolation):
        config = {"build": {"hooks": 9000}}
        project_config = ProjectConfig(isolation, config)

        with pytest.raises(TypeError, match="Field `tool.hatch.build.hooks` must be a table"):
            _ = project_config.build.target("foo").hook_config

    def test_hook_config_global_not_table(self, isolation):
        config = {"build": {"hooks": {"hook1": 9000}}}
        project_config = ProjectConfig(isolation, config)

        with pytest.raises(TypeError, match="Field `tool.hatch.build.hooks.hook1` must be a table"):
            _ = project_config.build.target("foo").hook_config

    def test_hooks_not_table(self, isolation):
        config = {"build": {"targets": {"foo": {"hooks": 9000}}}}
        project_config = ProjectConfig(isolation, config)

        with pytest.raises(TypeError, match="Field `tool.hatch.build.targets.foo.hooks` must be a table"):
            _ = project_config.build.target("foo").hook_config

    def test_hook_config_not_table(self, isolation):
        config = {"build": {"targets": {"foo": {"hooks": {"hook1": 9000}}}}}
        project_config = ProjectConfig(isolation, config)

        with pytest.raises(TypeError, match="Field `tool.hatch.build.targets.foo.hooks.hook1` must be a table"):
            _ = project_config.build.target("foo").hook_config

    def test_hook_config_target_override(self, isolation):
        config = {
            "build": {
                "hooks": {
                    "hook1": {"foo": "bar", "enable-by-default": False},
                    "hook2": {"foo": "bar"},
                    "hook3": {"foo": "bar"},
                    "hook4": {"foo": "bar"},
                },
                "targets": {
                    "foo": {
                        "hooks": {
                            "hook3": {"bar": "foo"},
                            "hook4": {"bar": "foo", "enable-by-default": False},
                            "hook5": {"bar": "foo"},
                            "hook6": {"bar": "foo", "enable-by-default": False},
                        },
                    },
                },
            }
        }
        project_config = ProjectConfig(isolation, config)

        hook_config = project_config.build.target("foo").hook_config
        assert hook_config == {
            "hook2": {"foo": "bar"},
            "hook3": {"bar": "foo"},
            "hook5": {"bar": "foo"},
        }

    def test_hook_config_all_enabled(self, isolation):
        config = {
            "build": {
                "hooks": {
                    "hook1": {"foo": "bar", "enable-by-default": False},
                    "hook2": {"foo": "bar"},
                    "hook3": {"foo": "bar"},
                    "hook4": {"foo": "bar"},
                },
                "targets": {
                    "foo": {
                        "hooks": {
                            "hook3": {"bar": "foo"},
                            "hook4": {"bar": "foo", "enable-by-default": False},
                            "hook5": {"bar": "foo"},
                            "hook6": {"bar": "foo", "enable-by-default": False},
                        },
                    },
                },
            }
        }
        project_config = ProjectConfig(isolation, config)

        with EnvVars({BuildEnvVars.HOOKS_ENABLE: "true"}):
            hook_config = project_config.build.target("foo").hook_config

        assert hook_config == {
            "hook1": {"foo": "bar", "enable-by-default": False},
            "hook2": {"foo": "bar"},
            "hook3": {"bar": "foo"},
            "hook4": {"bar": "foo", "enable-by-default": False},
            "hook5": {"bar": "foo"},
            "hook6": {"bar": "foo", "enable-by-default": False},
        }

    def test_hook_config_all_disabled(self, isolation):
        config = {
            "build": {
                "hooks": {
                    "hook1": {"foo": "bar", "enable-by-default": False},
                    "hook2": {"foo": "bar"},
                    "hook3": {"foo": "bar"},
                    "hook4": {"foo": "bar"},
                },
                "targets": {
                    "foo": {
                        "hooks": {
                            "hook3": {"bar": "foo"},
                            "hook4": {"bar": "foo", "enable-by-default": False},
                            "hook5": {"bar": "foo"},
                            "hook6": {"bar": "foo", "enable-by-default": False},
                        },
                    },
                },
            }
        }
        project_config = ProjectConfig(isolation, config)

        with EnvVars({BuildEnvVars.NO_HOOKS: "true"}):
            hook_config = project_config.build.target("foo").hook_config

        assert not hook_config

    def test_hook_config_specific_enabled(self, isolation):
        config = {
            "build": {
                "hooks": {
                    "hook1": {"foo": "bar", "enable-by-default": False},
                    "hook2": {"foo": "bar"},
                    "hook3": {"foo": "bar"},
                    "hook4": {"foo": "bar"},
                },
                "targets": {
                    "foo": {
                        "hooks": {
                            "hook3": {"bar": "foo"},
                            "hook4": {"bar": "foo", "enable-by-default": False},
                            "hook5": {"bar": "foo"},
                            "hook6": {"bar": "foo", "enable-by-default": False},
                        },
                    },
                },
            }
        }
        project_config = ProjectConfig(isolation, config)

        with EnvVars({f"{BuildEnvVars.HOOK_ENABLE_PREFIX}HOOK6": "true"}):
            hook_config = project_config.build.target("foo").hook_config

        assert hook_config == {
            "hook2": {"foo": "bar"},
            "hook3": {"bar": "foo"},
            "hook5": {"bar": "foo"},
            "hook6": {"bar": "foo", "enable-by-default": False},
        }
