"""Generic integration — bring your own agent.

Requires ``--commands-dir`` to specify the output directory for command
files.  No longer special-cased in the core CLI — just another
integration with its own required option.
"""

from __future__ import annotations

from pathlib import Path
from typing import Any

from ..base import IntegrationOption, MarkdownIntegration
from ..manifest import IntegrationManifest


class GenericIntegration(MarkdownIntegration):
    """Integration for user-specified (generic) agents."""

    key = "generic"
    config = {
        "name": "Generic (bring your own agent)",
        "folder": None,  # Set dynamically from --commands-dir
        "commands_subdir": "commands",
        "install_url": None,
        "requires_cli": False,
    }
    registrar_config = {
        "dir": "",  # Set dynamically from --commands-dir
        "format": "markdown",
        "args": "$ARGUMENTS",
        "extension": ".md",
    }
    context_file = "AGENTS.md"

    @classmethod
    def options(cls) -> list[IntegrationOption]:
        return [
            IntegrationOption(
                "--commands-dir",
                required=True,
                help="Directory for command files (e.g. .myagent/commands/)",
            ),
        ]

    @staticmethod
    def _resolve_commands_dir(
        parsed_options: dict[str, Any] | None,
        opts: dict[str, Any],
    ) -> str:
        """Extract ``--commands-dir`` from parsed options or raw_options.

        Returns the directory string or raises ``ValueError``.
        """
        parsed_options = parsed_options or {}

        commands_dir = parsed_options.get("commands_dir")
        if commands_dir:
            return commands_dir

        # Fall back to raw_options (--integration-options="--commands-dir ...")
        raw = opts.get("raw_options")
        if raw:
            import shlex
            tokens = shlex.split(raw)
            for i, token in enumerate(tokens):
                if token == "--commands-dir" and i + 1 < len(tokens):
                    return tokens[i + 1]
                if token.startswith("--commands-dir="):
                    return token.split("=", 1)[1]

        raise ValueError(
            "--commands-dir is required for the generic integration"
        )

    def commands_dest(self, project_root: Path) -> Path:
        """Not supported for GenericIntegration — use setup() directly.

        GenericIntegration is stateless; the output directory comes from
        ``parsed_options`` or ``raw_options`` at call time, not from
        instance state.
        """
        raise ValueError(
            "GenericIntegration.commands_dest() cannot be called directly; "
            "the output directory is resolved from parsed_options in setup()"
        )

    def setup(
        self,
        project_root: Path,
        manifest: IntegrationManifest,
        parsed_options: dict[str, Any] | None = None,
        **opts: Any,
    ) -> list[Path]:
        """Install commands to the user-provided commands directory."""
        commands_dir = self._resolve_commands_dir(parsed_options, opts)

        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 = (project_root / commands_dir).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 = "$ARGUMENTS"
        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")
            processed = self.process_template(
                raw, self.key, script_type, arg_placeholder,
                context_file=context_file_display,
            )
            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
