import os
import unittest
import yaml
import glob

class TestDependencyApplicationId(unittest.TestCase):
    def test_application_id_matches_folder_for_dependent_roles(self):
        """
        For any role A that depends on role B (listed under A/meta/main.yml → dependencies),
        if both A and B have vars/main.yml with application_id defined,
        then application_id must equal the role's folder name for both.
        """
        base_dir = os.path.dirname(__file__)
        roles_dir = os.path.abspath(os.path.join(base_dir, '..', '..', 'roles'))

        violations = []

        # Helper to load application_id if present
        def load_app_id(role_path):
            vars_file = os.path.join(role_path, 'vars', 'main.yml')
            if not os.path.isfile(vars_file):
                return None
            with open(vars_file, encoding='utf-8') as f:
                data = yaml.safe_load(f) or {}
            return data.get('application_id')

        # Iterate all roles
        for role_path in glob.glob(os.path.join(roles_dir, '*')):
            if not os.path.isdir(role_path):
                continue

            role_name = os.path.basename(role_path)
            meta_file = os.path.join(role_path, 'meta', 'main.yml')
            if not os.path.isfile(meta_file):
                continue

            with open(meta_file, encoding='utf-8') as f:
                meta = yaml.safe_load(f) or {}

            deps = meta.get('dependencies', [])
            if not isinstance(deps, list):
                continue

            # collect just the role names this role depends on
            dep_names = []
            for item in deps:
                if isinstance(item, dict) and 'role' in item:
                    dep_names.append(item['role'])
                elif isinstance(item, str):
                    dep_names.append(item)

            # load application_id for this role once
            app_id_role = load_app_id(role_path)
            for dep_name in dep_names:
                dep_path = os.path.join(roles_dir, dep_name)
                if not os.path.isdir(dep_path):
                    continue

                app_id_dep = load_app_id(dep_path)
                # only check if both app_ids are defined
                if app_id_role is None or app_id_dep is None:
                    continue

                # check role A
                if app_id_role != role_name:
                    violations.append(
                        f"{role_name}: application_id='{app_id_role}' ≠ folder name '{role_name}'"
                    )
                # check role B
                if app_id_dep != dep_name:
                    violations.append(
                        f"{dep_name}: application_id='{app_id_dep}' ≠ folder name '{dep_name}'"
                    )

        if violations:
            self.fail(
                "application_id mismatches between role folder names and vars/main.yml:\n"
                + "\n".join(violations)
            )

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