"""Tool for regex match, extract, and replace operations."""

from __future__ import annotations

import json
import re
from typing import Any

from .base import Tool

_MAX_MATCHES = 500
_MAX_TEXT_LEN = 500_000


class RegexTool(Tool):
    """Match, extract, or replace text using regular expressions."""

    @property
    def name(self) -> str:
        return "regex"

    @property
    def description(self) -> str:
        return (
            "Perform regex operations on text: match (find all), "
            "extract (capture groups), or replace."
        )

    @property
    def parameters(self) -> dict[str, Any]:
        return {
            "type": "object",
            "properties": {
                "action": {
                    "type": "string",
                    "enum": ["match", "extract", "replace", "split"],
                    "description": "Operation to perform.",
                },
                "pattern": {
                    "type": "string",
                    "description": "Regular expression pattern.",
                },
                "text": {
                    "type": "string",
                    "description": "Input text to process.",
                },
                "replacement": {
                    "type": "string",
                    "description": "Replacement string (for replace action). Supports \\1, \\2 backrefs.",
                },
                "flags": {
                    "type": "string",
                    "description": "Regex flags: i (ignorecase), m (multiline), s (dotall). Combine like 'ims'.",
                },
                "max_results": {
                    "type": "integer",
                    "description": "Maximum matches to return. Default 500.",
                },
            },
            "required": ["action", "pattern", "text"],
        }

    async def execute(self, **kwargs: Any) -> str:
        action = kwargs["action"]
        pattern = kwargs["pattern"]
        text = kwargs["text"]
        flags_str = kwargs.get("flags", "")
        max_results = min(kwargs.get("max_results", _MAX_MATCHES), _MAX_MATCHES)

        if len(text) > _MAX_TEXT_LEN:
            return json.dumps({"error": f"Text exceeds {_MAX_TEXT_LEN} character limit"})

        flags = 0
        for c in flags_str:
            if c == "i":
                flags |= re.IGNORECASE
            elif c == "m":
                flags |= re.MULTILINE
            elif c == "s":
                flags |= re.DOTALL

        try:
            compiled = re.compile(pattern, flags)
        except re.error as exc:
            return json.dumps({"error": f"Invalid regex: {exc}"})

        if action == "match":
            return self._match(compiled, text, max_results)
        if action == "extract":
            return self._extract(compiled, text, max_results)
        if action == "replace":
            replacement = kwargs.get("replacement", "")
            return self._replace(compiled, text, replacement)
        if action == "split":
            return self._split(compiled, text, max_results)
        return json.dumps({"error": f"Unknown action: {action}"})

    def _match(self, pattern: re.Pattern, text: str, max_results: int) -> str:
        matches = []
        for m in pattern.finditer(text):
            if len(matches) >= max_results:
                break
            matches.append({
                "match": m.group(),
                "start": m.start(),
                "end": m.end(),
            })
        return json.dumps({"ok": True, "action": "match", "count": len(matches), "matches": matches})

    def _extract(self, pattern: re.Pattern, text: str, max_results: int) -> str:
        matches = []
        for m in pattern.finditer(text):
            if len(matches) >= max_results:
                break
            groups = m.groups()
            groupdict = m.groupdict()
            matches.append({
                "full_match": m.group(),
                "groups": list(groups) if groups else [],
                "named_groups": groupdict if groupdict else {},
            })
        return json.dumps({"ok": True, "action": "extract", "count": len(matches), "matches": matches})

    def _replace(self, pattern: re.Pattern, text: str, replacement: str) -> str:
        result, count = pattern.subn(replacement, text)
        out: dict[str, Any] = {
            "ok": True,
            "action": "replace",
            "replacements": count,
        }
        if len(result) > _MAX_TEXT_LEN:
            out["result"] = result[:_MAX_TEXT_LEN] + "\n... [truncated]"
        else:
            out["result"] = result
        return json.dumps(out)

    def _split(self, pattern: re.Pattern, text: str, max_results: int) -> str:
        parts = pattern.split(text, maxsplit=max_results)
        return json.dumps({"ok": True, "action": "split", "count": len(parts), "parts": parts})
