import os
import glob
import re
import yaml
from docutils import nodes
from sphinx.util import logging
from docutils.parsers.rst import Directive

logger = logging.getLogger(__name__)

class RolesOverviewDirective(Directive):
    """
    A directive to embed a roles overview as reStructuredText.

    It scans the roles directory (i.e. every folder under "roles") for a "meta/main.yml" file,
    reads the role’s galaxy tags and description, and outputs an overview grouped by each tag.
    For each role, it attempts to extract a level‑1 heading from its README.md as the title.
    If no title is found, the role folder name is used.
    The title is rendered as a clickable link to the role's README.md.
    """
    has_content = False

    def run(self):
        env = self.state.document.settings.env
        srcdir = env.srcdir
        roles_dir = os.path.join(srcdir, 'roles')
        if not os.path.isdir(roles_dir):
            logger.warning(f"Roles directory not found: {roles_dir}")
            error_node = self.state.document.reporter.error(
                "Roles directory not found.", line=self.lineno)
            return [error_node]

        # Gather role entries grouped by tag.
        categories = {}
        for role_path in glob.glob(os.path.join(roles_dir, '*')):
            if os.path.isdir(role_path):
                meta_path = os.path.join(role_path, 'meta', 'main.yml')
                if os.path.exists(meta_path):
                    try:
                        with open(meta_path, 'r', encoding='utf-8') as f:
                            data = yaml.safe_load(f)
                    except Exception as e:
                        logger.warning(f"Error reading YAML file {meta_path}: {e}")
                        continue

                    role_name = os.path.basename(role_path)
                    # Determine title from README.md if present.
                    readme_path = os.path.join(role_path, 'README.md')
                    title = role_name
                    if os.path.exists(readme_path):
                        try:
                            with open(readme_path, 'r', encoding='utf-8') as f:
                                for line in f:
                                    match = re.match(r'^#\s+(.*)$', line)
                                    if match:
                                        title = match.group(1).strip()
                                        break
                        except Exception as e:
                            logger.warning(f"Error reading README.md for {role_name}: {e}")

                    galaxy_info = data.get('galaxy_info', {})
                    tags = galaxy_info.get('galaxy_tags', [])
                    if not tags:
                        tags = ['uncategorized']
                    role_description = galaxy_info.get('description', '')
                    role_entry = {
                        'name': role_name,
                        'title': title,
                        'description': role_description,
                        'link': f'roles/{role_name}/README.md',
                        'tags': tags,
                    }
                    for tag in tags:
                        categories.setdefault(tag, []).append(role_entry)
                else:
                    logger.warning(f"meta/main.yml not found for role {role_path}")

        # Sort categories and roles alphabetically.
        sorted_categories = sorted(categories.items(), key=lambda x: x[0].lower())
        for tag, roles in sorted_categories:
            roles.sort(key=lambda r: r['name'].lower())

        # Build document structure.
        container = nodes.container()

        # For each category, create a section to serve as a large category heading.
        for tag, roles in sorted_categories:
            # Create a section for the category.
            cat_id = nodes.make_id(tag)
            category_section = nodes.section(ids=[cat_id])
            category_title = nodes.title(text=tag)
            category_section += category_title

            # For each role within the category, create a subsection.
            for role in roles:
                role_section_id = nodes.make_id(role['title'])
                role_section = nodes.section(ids=[role_section_id])
                # Create a title node with a clickable reference.
                role_title = nodes.title()
                reference = nodes.reference(text=role['title'], refuri=role['link'])
                role_title += reference
                role_section += role_title

                if role['description']:
                    para = nodes.paragraph(text=role['description'])
                    role_section += para

                category_section += role_section

            container += category_section

        return [container]

def setup(app):
    app.add_directive("roles-overview", RolesOverviewDirective)
    return {'version': '0.1', 'parallel_read_safe': True}