# File: src/mcp_servers/noveler/tools/emotion/base_emotion_tool.py
# Purpose: Provide shared interfaces, validation, and response helpers for emotion MCP tools.
# Context: Imported by SPEC-A38 emotion tools within the noveler MCP server to standardise behaviour.

"""Base class for SPEC-A38 emotion MCP tools.

Purpose:
    Supply common interfaces for execution, validation, and response formatting across emotion tools.
Context:
    Shared foundation for noveler MCP emotion utilities, ensuring consistent behaviour and logging.
Side Effects:
    Creates a namespaced logger during initialisation.
"""

from abc import ABC, abstractmethod
from dataclasses import dataclass
from enum import Enum
from typing import Any

from noveler.infrastructure.logging.unified_logger import get_logger


class EmotionLayer(Enum):
    """Enumerates the five emotion-expression layers used by SPEC-A38.

    Purpose:
        Provide canonical layer identifiers consumed by downstream tools.
    Side Effects:
        None.
    """
    PHYSICAL = "physical"      # 身体層：体温、震え、姿勢
    VISCERAL = "visceral"      # 内臓層：胃のもたれ、息苦しさ
    CARDIAC = "cardiac"        # 心拍呼吸層：動悸、呼吸の乱れ
    NEURAL = "neural"          # 神経歪み層：思考の混乱、集中力低下
    METAPHORICAL = "metaphorical"  # 比喩層：抽象的表現、詩的比喩


class EmotionIntensity(Enum):
    """Enumerates intensity levels accepted by emotion tools.

    Purpose:
        Normalise intensity inputs across all emotion MCP tools.
    Side Effects:
        None.
    """
    MINIMAL = 1
    LOW = 3
    MODERATE = 5
    HIGH = 7
    EXTREME = 10


@dataclass
class EmotionToolInput:
    """Input payload shared by all emotion MCP tools.

    Purpose:
        Carry text, contextual metadata, and optional configuration into tool execution.
    Side Effects:
        None.
    """
    text: str
    emotion_layer: EmotionLayer | None = None
    intensity: EmotionIntensity | None = None
    context: dict[str, Any] | None = None
    metadata: dict[str, Any] | None = None


@dataclass
class EmotionToolOutput:
    """Standardised response structure for emotion MCP tools.

    Purpose:
        Provide a consistent container for tool outcomes, analysis, and metadata.
    Side Effects:
        None.
    """
    success: bool
    tool_name: str
    score: float | None = None
    analysis: dict[str, Any] | None = None
    suggestions: list[str] | None = None
    issues: list[str] | None = None
    metadata: dict[str, Any] | None = None
    error_message: str | None = None


class BaseEmotionTool(ABC):
    """Abstract base class for SPEC-A38 emotion tools.

    Purpose:
        Define shared lifecycle hooks, execution wrappers, and response helpers.
    Side Effects:
        Instantiates a logger scoped to the derived tool.
    """

    def __init__(self, tool_name: str) -> None:
        """Initialise the base tool with a namespaced logger.

        Purpose:
            Store the tool identifier and prepare logging before derived initialisation runs.

        Args:
            tool_name: Identifier used in logs and response metadata.
        Side Effects:
            Creates a logger via `get_logger` and calls `_initialize_tool`.
        """
        self.tool_name = tool_name
        self.logger = get_logger(f"emotion_tools.{tool_name}")
        self._initialize_tool()

    def _initialize_tool(self) -> None:
        """Hook for derived classes to perform additional initialisation.

        Purpose:
            Allow subclasses to allocate resources after base initialisation.
        Side Effects:
            Defined by derived classes; default implementation is a no-op.
        """

    @abstractmethod
    async def execute(self, input_data: EmotionToolInput) -> EmotionToolOutput:
        """Run the main tool logic (must be implemented by subclasses).

        Purpose:
            Define the core analysis performed by a specific emotion tool.

        Args:
            input_data: Prepared tool input payload.

        Returns:
            EmotionToolOutput produced by the concrete tool.
        Side Effects:
            Determined by subclasses.
        """

    def validate_input(self, input_data: EmotionToolInput) -> bool:
        """Validate that required fields exist in the tool input.

        Purpose:
            Prevent downstream processing when the text payload is missing or empty.

        Args:
            input_data: Tool input to validate.

        Returns:
            True when the input is acceptable, otherwise False.
        Side Effects:
            Logs a warning when validation fails.
        """
        if not input_data.text or not input_data.text.strip():
            self.logger.warning(
                "%s: 空のテキスト入力",
                self.tool_name,
            )
            return False
        return True

    def create_success_output(
        self,
        score: float | None = None,
        analysis: dict[str, Any] | None = None,
        suggestions: list[str] | None = None,
        metadata: dict[str, Any] | None = None
    ) -> EmotionToolOutput:
        """Build a standard success response for emotion tools.

        Purpose:
            Simplify creation of successful EmotionToolOutput instances.

        Args:
            score: Optional numeric score to include.
            analysis: Optional analysis payload.
            suggestions: Optional list of improvement suggestions.
            metadata: Optional dictionary of additional metadata.

        Returns:
            EmotionToolOutput marked as successful.
        Side Effects:
            None.
        Preconditions:
            None.
        """
        return EmotionToolOutput(
            success=True,
            tool_name=self.tool_name,
            score=score,
            analysis=analysis or {},
            suggestions=suggestions or [],
            metadata=metadata or {}
        )

    def create_error_output(
        self,
        error_message: str,
        issues: list[str] | None = None
    ) -> EmotionToolOutput:
        """エラーレスポンス生成

        Args:
            error_message: エラーメッセージ
            issues: 問題リスト

        Returns:
            エラーレスポンス
        """
        self.logger.error(
            "%s: %s",
            self.tool_name,
            error_message,
        )
        return EmotionToolOutput(
            success=False,
            tool_name=self.tool_name,
            error_message=error_message,
            issues=issues or []
        )

    async def safe_execute(self, input_data: EmotionToolInput) -> EmotionToolOutput:
        """安全な実行ラッパー

        エラーハンドリングと共通処理を含む実行メソッド。

        Args:
            input_data: 入力データ

        Returns:
            処理結果（エラー時も含む）
        """
        try:
            # 入力検証
            if not self.validate_input(input_data):
                return self.create_error_output(
                    "無効な入力データ",
                    ["テキストが空または無効です"]
                )

            self.logger.info(
                "%s: 実行開始",
                self.tool_name,
            )

            # 主要処理実行
            result = await self.execute(input_data)

            self.logger.info(
                "%s: 実行完了",
                self.tool_name,
            )
            return result

        except Exception as e:
            return self.create_error_output(
                f"実行時エラー: {e!s}",
                [f"例外: {type(e).__name__}"]
            )

    def get_tool_info(self) -> dict[str, Any]:
        """ツール情報取得

        Returns:
            ツール基本情報
        """
        return {
            "name": self.tool_name,
            "version": "1.0.0",
            "spec": "SPEC-A38-EMOTION-001",
            "supported_layers": [layer.value for layer in EmotionLayer],
            "supported_intensities": [intensity.value for intensity in EmotionIntensity]
        }
