"""Forge integration — forgecode.dev AI coding agent.

Forge has several unique behaviors compared to standard markdown agents:
- Uses `{{parameters}}` instead of `$ARGUMENTS` for argument passing
- Strips `handoffs` frontmatter key (Claude Code feature that causes Forge to hang)
- Injects `name` field into frontmatter when missing
- Uses a hyphenated frontmatter `name` value (e.g., `speckit-foo-bar`) for shell compatibility, especially with ZSH
"""

from __future__ import annotations

from pathlib import Path
from typing import Any

from ..base import MarkdownIntegration
from ..manifest import IntegrationManifest


def format_forge_command_name(cmd_name: str) -> str:
    """Convert command name to Forge-compatible hyphenated format.
    
    Forge requires command names to use hyphens instead of dots for
    compatibility with ZSH and other shells. This function converts
    dot-notation command names to hyphenated format.
    
    The function is idempotent: already-formatted names are returned unchanged.
    
    Examples:
        >>> format_forge_command_name("plan")
        'speckit-plan'
        >>> format_forge_command_name("speckit.plan")
        'speckit-plan'
        >>> format_forge_command_name("speckit-plan")
        'speckit-plan'
        >>> format_forge_command_name("speckit.my-extension.example")
        'speckit-my-extension-example'
        >>> format_forge_command_name("speckit-my-extension-example")
        'speckit-my-extension-example'
        >>> format_forge_command_name("speckit.jira.sync-status")
        'speckit-jira-sync-status'
    
    Args:
        cmd_name: Command name in dot notation (speckit.foo.bar), 
                  hyphenated format (speckit-foo-bar), or plain name (foo)
    
    Returns:
        Hyphenated command name with 'speckit-' prefix
    """
    # Already in hyphenated format - return as-is (idempotent)
    if cmd_name.startswith("speckit-"):
        return cmd_name
    
    # Strip 'speckit.' prefix if present
    short_name = cmd_name
    if short_name.startswith("speckit."):
        short_name = short_name[len("speckit."):]
    
    # Replace all dots with hyphens
    short_name = short_name.replace(".", "-")
    
    # Return with 'speckit-' prefix
    return f"speckit-{short_name}"


class ForgeIntegration(MarkdownIntegration):
    """Integration for Forge (forgecode.dev).

    Extends MarkdownIntegration to add Forge-specific processing:
    - Replaces $ARGUMENTS with {{parameters}}
    - Strips 'handoffs' frontmatter key (incompatible with Forge)
    - Injects 'name' field into frontmatter when missing
    """

    key = "forge"
    config = {
        "name": "Forge",
        "folder": ".forge/",
        "commands_subdir": "commands",
        "install_url": "https://forgecode.dev/docs/",
        "requires_cli": True,
    }
    registrar_config = {
        "dir": ".forge/commands",
        "format": "markdown",
        "args": "{{parameters}}",
        "extension": ".md",
        "strip_frontmatter_keys": ["handoffs"],
        "inject_name": True,
        "format_name": format_forge_command_name,  # Custom name formatter
        "invoke_separator": "-",
    }
    context_file = "AGENTS.md"
    invoke_separator = "-"

    def setup(
        self,
        project_root: Path,
        manifest: IntegrationManifest,
        parsed_options: dict[str, Any] | None = None,
        **opts: Any,
    ) -> list[Path]:
        """Install Forge commands with custom processing.

        Extends MarkdownIntegration.setup() to inject Forge-specific transformations
        after standard template processing.
        """
        templates = self.list_command_templates()
        if not templates:
            return []

        project_root_resolved = project_root.resolve()
        if manifest.project_root != project_root_resolved:
            raise ValueError(
                f"manifest.project_root ({manifest.project_root}) does not match "
                f"project_root ({project_root_resolved})"
            )

        dest = self.commands_dest(project_root).resolve()
        try:
            dest.relative_to(project_root_resolved)
        except ValueError as exc:
            raise ValueError(
                f"Integration destination {dest} escapes "
                f"project root {project_root_resolved}"
            ) from exc
        dest.mkdir(parents=True, exist_ok=True)

        script_type = opts.get("script_type", "sh")
        arg_placeholder = self.registrar_config.get("args", "{{parameters}}")
        created: list[Path] = []
        context_file_display = self._context_file_display(project_root)

        for src_file in templates:
            raw = src_file.read_text(encoding="utf-8")
            # Process template with standard MarkdownIntegration logic
            processed = self.process_template(
                raw, self.key, script_type, arg_placeholder,
                context_file=context_file_display,
                invoke_separator=self.invoke_separator,
            )

            # FORGE-SPECIFIC: Ensure any remaining $ARGUMENTS placeholders are
            # converted to {{parameters}}
            processed = processed.replace("$ARGUMENTS", arg_placeholder)

            # FORGE-SPECIFIC: Apply frontmatter transformations
            processed = self._apply_forge_transformations(processed, src_file.stem)

            dst_name = self.command_filename(src_file.stem)
            dst_file = self.write_file_and_record(
                processed, dest / dst_name, project_root, manifest
            )
            created.append(dst_file)

        # Upsert managed context section into the agent context file
        self.upsert_context_section(project_root)

        return created

    def _apply_forge_transformations(self, content: str, template_name: str) -> str:
        """Apply Forge-specific transformations to processed content.

        1. Strip 'handoffs' frontmatter key (from Claude Code templates; incompatible with Forge)
        2. Inject 'name' field if missing (using hyphenated format)
        """
        # Parse frontmatter
        lines = content.split('\n')
        if not lines or lines[0].strip() != '---':
            return content

        # Find end of frontmatter
        frontmatter_end = -1
        for i in range(1, len(lines)):
            if lines[i].strip() == '---':
                frontmatter_end = i
                break

        if frontmatter_end == -1:
            return content

        frontmatter_lines = lines[1:frontmatter_end]
        body_lines = lines[frontmatter_end + 1:]

        # 1. Strip 'handoffs' key
        filtered_frontmatter = []
        skip_until_outdent = False
        for line in frontmatter_lines:
            if skip_until_outdent:
                # Skip indented lines under handoffs:
                if line and (line[0] == ' ' or line[0] == '\t'):
                    continue
                else:
                    skip_until_outdent = False

            if line.strip().startswith('handoffs:'):
                skip_until_outdent = True
                continue

            filtered_frontmatter.append(line)

        # 2. Inject 'name' field if missing (using centralized formatter)
        has_name = any(line.strip().startswith('name:') for line in filtered_frontmatter)
        if not has_name:
            # Use centralized formatter to ensure consistent hyphenated format
            cmd_name = format_forge_command_name(template_name)
            filtered_frontmatter.insert(0, f'name: {cmd_name}')

        # Reconstruct content
        result = ['---'] + filtered_frontmatter + ['---'] + body_lines
        return '\n'.join(result)
