#!/usr/bin/env python3
"""
Exchange Rate MCP Server - Real-time exchange rate data
Uses free exchangerate-api.com
"""
import os
import sys
import json
import asyncio
import logging
from typing import Any, Dict, List, Optional
from datetime import datetime
import aiohttp
from mcp.server import Server, NotificationOptions
from mcp.server.models import InitializationOptions
import mcp.server.stdio
import mcp.types as types

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class ExchangeRateServer:
    def __init__(self):
        # Use free exchangerate-api.com
        self.base_url = "https://api.exchangerate-api.com/v4/latest"
        self.server = Server("exchange-rate")
        
        # Setup tool list handler
        @self.server.list_tools()
        async def handle_list_tools() -> List[types.Tool]:
            return [
                self._get_exchange_rate_tool(),
                self._convert_currency_tool(),
                self._get_all_rates_tool(),
                self._list_supported_currencies_tool()
            ]
        
        # Setup tool call handler
        @self.server.call_tool()
        async def handle_call_tool(name: str, arguments: Optional[Dict[str, Any]]) -> List[types.TextContent]:
            return await self._handle_tool_call(name, arguments or {})
    
    def _get_exchange_rate_tool(self) -> types.Tool:
        return types.Tool(
            name="get_exchange_rate",
            description="Get exchange rate between two currencies",
            inputSchema={
                "type": "object",
                "properties": {
                    "from_currency": {
                        "type": "string",
                        "description": "Source currency code (e.g., USD, EUR, CNY)"
                    },
                    "to_currency": {
                        "type": "string",
                        "description": "Target currency code (e.g., USD, EUR, CNY)"
                    }
                },
                "required": ["from_currency", "to_currency"]
            }
        )
    
    def _convert_currency_tool(self) -> types.Tool:
        return types.Tool(
            name="convert_currency",
            description="Convert amount from one currency to another",
            inputSchema={
                "type": "object",
                "properties": {
                    "amount": {
                        "type": "number",
                        "description": "Amount to convert"
                    },
                    "from_currency": {
                        "type": "string",
                        "description": "Source currency code"
                    },
                    "to_currency": {
                        "type": "string",
                        "description": "Target currency code"
                    }
                },
                "required": ["amount", "from_currency", "to_currency"]
            }
        )
    
    def _get_all_rates_tool(self) -> types.Tool:
        return types.Tool(
            name="get_all_rates",
            description="Get all exchange rates for a base currency",
            inputSchema={
                "type": "object",
                "properties": {
                    "base_currency": {
                        "type": "string",
                        "description": "Base currency code (default: USD)",
                        "default": "USD"
                    }
                },
                "required": []
            }
        )
    
    def _list_supported_currencies_tool(self) -> types.Tool:
        return types.Tool(
            name="list_supported_currencies",
            description="List all supported currency codes",
            inputSchema={
                "type": "object",
                "properties": {},
                "required": []
            }
        )
    
    async def _make_request(self, base_currency: str = "USD") -> Dict[str, Any]:
        """Make API request to exchangerate-api.com"""
        url = f"{self.base_url}/{base_currency.upper()}"
        
        async with aiohttp.ClientSession() as session:
            try:
                async with session.get(url, timeout=30) as response:
                    if response.status == 200:
                        return await response.json()
                    else:
                        return {"error": f"API returned status {response.status}"}
                        
            except asyncio.TimeoutError:
                return {"error": "Request timeout"}
            except Exception as e:
                return {"error": f"Request failed: {str(e)}"}
    
    async def _handle_tool_call(self, name: str, arguments: Dict[str, Any]) -> List[types.TextContent]:
        """Handle tool calls"""
        try:
            if name == "get_exchange_rate":
                from_currency = arguments["from_currency"].upper()
                to_currency = arguments["to_currency"].upper()
                
                # Get rates for the base currency
                data = await self._make_request(from_currency)
                
                if "error" in data:
                    result = data
                elif "rates" in data and to_currency in data["rates"]:
                    rate = data["rates"][to_currency]
                    result = {
                        "from": from_currency,
                        "to": to_currency,
                        "rate": rate,
                        "date": data.get("date", ""),
                        "inverse_rate": 1/rate if rate > 0 else 0
                    }
                else:
                    result = {"error": f"Currency {to_currency} not found"}
                    
            elif name == "convert_currency":
                amount = float(arguments["amount"])
                from_currency = arguments["from_currency"].upper()
                to_currency = arguments["to_currency"].upper()
                
                # Get rates
                data = await self._make_request(from_currency)
                
                if "error" in data:
                    result = data
                elif "rates" in data and to_currency in data["rates"]:
                    rate = data["rates"][to_currency]
                    converted = amount * rate
                    result = {
                        "from": from_currency,
                        "to": to_currency,
                        "amount": amount,
                        "converted_amount": round(converted, 2),
                        "rate": rate,
                        "date": data.get("date", "")
                    }
                else:
                    result = {"error": f"Currency {to_currency} not found"}
                    
            elif name == "get_all_rates":
                base_currency = arguments.get("base_currency", "USD").upper()
                data = await self._make_request(base_currency)
                
                if "error" in data:
                    result = data
                else:
                    result = {
                        "base": base_currency,
                        "date": data.get("date", ""),
                        "rates": data.get("rates", {})
                    }
                    
            elif name == "list_supported_currencies":
                # Get USD rates to see all supported currencies
                data = await self._make_request("USD")
                
                if "error" in data:
                    result = data
                elif "rates" in data:
                    currencies = sorted(list(data["rates"].keys()))
                    result = {
                        "currencies": currencies,
                        "total": len(currencies),
                        "common_currencies": {
                            "USD": "US Dollar",
                            "EUR": "Euro",
                            "GBP": "British Pound",
                            "JPY": "Japanese Yen",
                            "CNY": "Chinese Yuan",
                            "AUD": "Australian Dollar",
                            "CAD": "Canadian Dollar",
                            "CHF": "Swiss Franc",
                            "HKD": "Hong Kong Dollar",
                            "SGD": "Singapore Dollar",
                            "INR": "Indian Rupee",
                            "KRW": "South Korean Won",
                            "MXN": "Mexican Peso",
                            "BRL": "Brazilian Real",
                            "RUB": "Russian Ruble"
                        }
                    }
                else:
                    result = {"error": "Failed to get currency list"}
                    
            else:
                result = {"error": f"Unknown tool: {name}"}
            
            return [types.TextContent(
                type="text",
                text=json.dumps(result, indent=2)
            )]
            
        except Exception as e:
            logger.error(f"Error in tool {name}: {e}")
            return [types.TextContent(
                type="text",
                text=json.dumps({"error": str(e)})
            )]
    
    async def run(self):
        """Run the server"""
        async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
            await self.server.run(
                read_stream,
                write_stream,
                InitializationOptions(
                    server_name="exchange-rate",
                    server_version="0.1.0",
                    capabilities=self.server.get_capabilities(
                        notification_options=NotificationOptions(),
                        experimental_capabilities={},
                    ),
                ),
            )

async def main():
    server = ExchangeRateServer()
    await server.run()

if __name__ == "__main__":
    asyncio.run(main())
