"""
Database MCP Tool Provider - ADR-015 模組化架構
==============================================

提供資料庫查詢工具：
- list_approvals: 列出 Approval 請求
- get_approval: 取得單一 Approval 詳情
- list_incidents: 列出活躍事件
- list_timeline: 列出時間線事件

透過 DI 注入 Services，不直接 import。

@see docs/adr/ADR-015-mcp-modular-architecture.md
"""

import uuid
from typing import Any
from uuid import UUID

import structlog

from src.plugins.mcp.interfaces import MCPTool, MCPToolProvider, MCPToolResult

logger = structlog.get_logger(__name__)


class DatabaseProvider(MCPToolProvider):
    """
    Database MCP Tool Provider

    封裝所有 Approval/Incident 資料庫查詢操作。
    """

    def __init__(self) -> None:
        self._approval_svc = None
        self._incident_svc = None
        self._timeline_svc = None

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

    def _get_approval_service(self):
        """Lazy load approval service"""
        if self._approval_svc is None:
            from src.services.approval_db import get_approval_service
            self._approval_svc = get_approval_service()
        return self._approval_svc

    def _get_incident_service(self):
        """Lazy load incident service"""
        if self._incident_svc is None:
            from src.services.incident_service import get_incident_service
            self._incident_svc = get_incident_service()
        return self._incident_svc

    def _get_timeline_service(self):
        """Lazy load timeline service"""
        if self._timeline_svc is None:
            from src.services.approval_db import get_timeline_service
            self._timeline_svc = get_timeline_service()
        return self._timeline_svc

    async def list_tools(self) -> list[MCPTool]:
        return [
            MCPTool(
                name="list_approvals",
                description="List approval requests with optional status filter",
                input_schema={
                    "type": "object",
                    "properties": {
                        "status": {"type": "string", "description": "Filter by status: pending, approved, rejected, expired"},
                        "limit": {"type": "integer", "description": "Max results (default: 20)"},
                    },
                },
                server_name=self.name,
            ),
            MCPTool(
                name="get_approval",
                description="Get detailed information about a specific approval",
                input_schema={
                    "type": "object",
                    "properties": {
                        "approval_id": {"type": "string", "description": "Approval UUID"},
                    },
                    "required": ["approval_id"],
                },
                server_name=self.name,
            ),
            MCPTool(
                name="list_incidents",
                description="List incidents with optional status filter",
                input_schema={
                    "type": "object",
                    "properties": {
                        "status": {"type": "string", "description": "Filter by status: active, resolved, escalated"},
                        "limit": {"type": "integer", "description": "Max results (default: 20)"},
                    },
                },
                server_name=self.name,
            ),
            MCPTool(
                name="list_timeline",
                description="List timeline events for audit trail",
                input_schema={
                    "type": "object",
                    "properties": {
                        "limit": {"type": "integer", "description": "Max results (default: 50)"},
                    },
                },
                server_name=self.name,
            ),
        ]

    async def execute(
        self,
        tool_name: str,
        parameters: dict[str, Any],
    ) -> MCPToolResult:
        execution_id = str(uuid.uuid4())[:8]

        try:
            if tool_name == "list_approvals":
                output = await self._list_approvals(parameters)
            elif tool_name == "get_approval":
                output = await self._get_approval(parameters)
            elif tool_name == "list_incidents":
                output = await self._list_incidents(parameters)
            elif tool_name == "list_timeline":
                output = await self._list_timeline(parameters)
            else:
                return MCPToolResult(
                    success=False,
                    execution_id=execution_id,
                    error=f"Unknown tool: {tool_name}",
                )

            return MCPToolResult(
                success=True,
                execution_id=execution_id,
                output=output,
            )

        except Exception as e:
            logger.exception("database_provider_error", tool=tool_name, error=str(e))
            return MCPToolResult(
                success=False,
                execution_id=execution_id,
                error=str(e),
            )

    async def _list_approvals(self, parameters: dict) -> dict:
        from src.models.approval import ApprovalStatus

        approval_svc = self._get_approval_service()
        status_str = parameters.get("status")
        limit = parameters.get("limit", 20)

        status_filter = None
        if status_str:
            try:
                status_filter = ApprovalStatus(status_str.lower())
            except ValueError:
                return {"error": f"Invalid status: {status_str}. Valid: pending, approved, rejected, expired"}

        approvals = await approval_svc.get_all_approvals(
            status=status_filter,
            limit=limit,
        )

        return {
            "count": len(approvals),
            "approvals": [
                {
                    "id": str(a.id),
                    "action": a.action[:80] if a.action else "",
                    "status": a.status.value if hasattr(a.status, 'value') else str(a.status),
                    "risk_level": a.risk_level.value if hasattr(a.risk_level, 'value') else str(a.risk_level),
                    "signatures": f"{a.current_signatures}/{a.required_signatures}",
                    "created_at": a.created_at.isoformat() if a.created_at else None,
                }
                for a in approvals
            ],
        }

    async def _get_approval(self, parameters: dict) -> dict:
        approval_id = parameters.get("approval_id")
        if not approval_id:
            return {"error": "Missing 'approval_id' parameter"}

        approval_svc = self._get_approval_service()
        try:
            approval = await approval_svc.get_approval_by_id(UUID(approval_id))
        except ValueError:
            return {"error": f"Invalid UUID format: {approval_id}"}

        if not approval:
            return {"error": f"Approval not found: {approval_id}"}

        return {
            "id": str(approval.id),
            "action": approval.action,
            "description": approval.description,
            "status": approval.status.value if hasattr(approval.status, 'value') else str(approval.status),
            "risk_level": approval.risk_level.value if hasattr(approval.risk_level, 'value') else str(approval.risk_level),
            "required_signatures": approval.required_signatures,
            "current_signatures": approval.current_signatures,
            "signatures": [
                {"signer": s.signer_name, "timestamp": s.timestamp.isoformat()}
                for s in (approval.signatures or [])
            ],
            "created_at": approval.created_at.isoformat() if approval.created_at else None,
            "resolved_at": approval.resolved_at.isoformat() if approval.resolved_at else None,
        }

    async def _list_incidents(self, parameters: dict) -> dict:
        incident_svc = self._get_incident_service()
        status_filter = parameters.get("status")
        limit = parameters.get("limit", 20)

        incidents = await incident_svc.get_active_incidents()

        # Status filter
        if status_filter:
            incidents = [i for i in incidents if i.status.value == status_filter.lower()]

        incidents = incidents[:limit]

        return {
            "count": len(incidents),
            "incidents": [
                {
                    "id": i.incident_id,
                    "severity": i.severity.value if hasattr(i.severity, 'value') else str(i.severity),
                    "status": i.status.value if hasattr(i.status, 'value') else str(i.status),
                    "affected_services": i.affected_services,
                    "created_at": i.created_at.isoformat() if i.created_at else None,
                }
                for i in incidents
            ],
        }

    async def _list_timeline(self, parameters: dict) -> dict:
        timeline_svc = self._get_timeline_service()
        limit = parameters.get("limit", 50)

        events = await timeline_svc.get_events(limit=limit)

        return {
            "count": len(events),
            "events": events,
        }

    async def health_check(self) -> bool:
        """Check if database services are accessible"""
        try:
            # Try to get approval service
            self._get_approval_service()
            return True
        except Exception:
            return False
