"""
SET_SECRET action.

Migrated from the flat actions.py for modular organization.
"""

import re
import logging
from typing import Optional, Dict

from elizaos.runtime import AgentRuntime
from elizaos.types import Action, Message

from ..types import SecretLevel, SecretContext


logger = logging.getLogger(__name__)


def mask_secret(value: str, visible_chars: int = 4) -> str:
    """Mask a secret value for safe display."""
    if len(value) <= visible_chars * 2:
        return "*" * len(value)
    return value[:visible_chars] + "*" * (len(value) - visible_chars * 2) + value[-visible_chars:]


class SetSecretAction(Action):
    """Action to set a secret via natural language."""

    name = "SET_SECRET"
    description = "Set a secret/API key for the agent. Use when the user wants to configure or store a secret."
    similes = [
        "configure secret", "store api key", "set api key",
        "add secret", "save credential",
    ]
    examples = [
        [
            {"user": "user", "content": {"text": "Set my OpenAI key to sk-abc123xyz"}},
            {"user": "assistant", "content": {"text": "I've saved your OpenAI API key."}},
        ],
        [
            {"user": "user", "content": {"text": "Configure ANTHROPIC_API_KEY as sk-ant-mykey123"}},
            {"user": "assistant", "content": {"text": "I've configured your Anthropic API key."}},
        ],
    ]

    async def validate(self, runtime: AgentRuntime, message: Message) -> bool:
        text = message.content.get("text", "").lower() if isinstance(message.content, dict) else str(message.content).lower()
        keywords = ["set", "configure", "store", "save", "add"]
        secret_keywords = ["secret", "key", "api", "token", "credential", "password"]
        return any(kw in text for kw in keywords) and any(kw in text for kw in secret_keywords)

    async def handler(self, runtime: AgentRuntime, message: Message, state: Dict) -> Dict:
        from ..service import SecretsService

        secrets_service: SecretsService = runtime.get_service(SecretsService.service_type)
        if not secrets_service:
            return {"success": False, "message": "Secrets service not available"}

        text = message.content.get("text", "") if isinstance(message.content, dict) else str(message.content)
        extraction = await self._extract_secret_info(runtime, text)

        if not extraction.get("key") or not extraction.get("value"):
            return {
                "success": False,
                "message": "Could not extract secret key and value. Please specify the secret name and value.",
            }

        key = extraction["key"]
        value = extraction["value"]
        level = SecretLevel(extraction.get("level", "global"))
        description = extraction.get("description", "")
        secret_type = extraction.get("type", "api_key")

        context = SecretContext(
            level=level,
            agent_id=runtime.agent_id,
            user_id=getattr(message, "user_id", None),
            world_id=getattr(message, "room_id", None) if level == SecretLevel.WORLD else None,
        )

        config = {"description": description, "type": secret_type}
        success = await secrets_service.set(key, value, context, config)

        if success:
            return {"success": True, "message": f"Successfully set secret '{key}' with value {mask_secret(value)}"}
        return {"success": False, "message": f"Failed to set secret '{key}'"}

    async def _extract_secret_info(self, runtime: AgentRuntime, text: str) -> Dict:
        """Extract secret information from text using pattern matching and LLM fallback."""
        patterns = [
            r"(?:set|configure|store|save)\s+(?:the\s+)?(?:secret\s+)?([A-Z_][A-Z0-9_]*)\s+(?:to|as|=)\s+([^\s]+)",
            r"([A-Z_][A-Z0-9_]*)\s*[:=]\s*([^\s]+)",
            r"(?:api\s*key|secret|token)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s+(?:is|to|as|=)\s+([^\s]+)",
        ]
        for pattern in patterns:
            match = re.search(pattern, text, re.IGNORECASE)
            if match:
                return {
                    "key": match.group(1).upper(),
                    "value": match.group(2),
                    "level": "global",
                    "type": "api_key",
                }

        # LLM fallback
        import json
        prompt = (
            f'Extract the secret information from this message:\n"{text}"\n\n'
            f'Return ONLY a JSON object with: key, value, description, type, level\n'
            f'If you cannot find a key or value, return {{"key": null, "value": null}}'
        )
        try:
            response = await runtime.generate_text(prompt, {"temperature": 0.1, "max_tokens": 200})
            json_match = re.search(r"\{[^}]+\}", response)
            if json_match:
                return json.loads(json_match.group())
        except Exception:
            pass

        return {"key": None, "value": None}
