from fastmcp import FastMCP
from fastmcp.server.dependencies import get_http_request, get_http_headers
from pydantic import Field
from typing import Annotated
import random
import logging
import sys
import threading
import time
import glob
import os
from datetime import datetime, timedelta
from pathlib import Path
import json

# 日志持久化配置
LOG_DIR = Path("logs")
LOG_DIR.mkdir(exist_ok=True)
MAX_LOG_SIZE = 5 * 1024 * 1024  # 5MB = 5 * 1024 * 1024 字节
LOG_CLEANUP_DAYS = 30  # 保留30天的日志
LOG_CLEANUP_INTERVAL = 86400  # 每天检查一次清理 = 86400秒

class SizeBasedRotatingLogHandler:
    """基于文件大小的日志轮转处理器"""

    def __init__(self, log_dir: Path, max_size: int, cleanup_days: int, cleanup_interval: int):
        self.log_dir = log_dir
        self.max_size = max_size
        self.cleanup_days = cleanup_days
        self.cleanup_interval = cleanup_interval
        self.current_handler = None
        self.current_log_file = None
        self.log_counter = 1
        self.last_cleanup = time.time()
        self.lock = threading.Lock()

        # 创建初始日志文件
        self._rotate_log()

        # 启动清理线程
        self.cleanup_thread = threading.Thread(target=self._cleanup_worker, daemon=True)
        self.cleanup_thread.start()

    def _get_log_filename(self):
        """生成日志文件名，包含日期和序号"""
        date_str = datetime.now().strftime("%Y%m%d")
        return self.log_dir / f"mcpstorewiki_{date_str}_{self.log_counter:03d}.log"

    def _get_current_log_size(self):
        """获取当前日志文件大小"""
        if self.current_log_file and self.current_log_file.exists():
            return self.current_log_file.stat().st_size
        return 0

    def _should_rotate(self):
        """检查是否需要轮转日志"""
        return self._get_current_log_size() >= self.max_size

    def _rotate_log(self):
        """轮转日志文件"""
        with self.lock:
            # 关闭当前处理器
            if self.current_handler:
                logger.removeHandler(self.current_handler)
                self.current_handler.close()

            # 创建新的文件处理器
            self.current_log_file = self._get_log_filename()
            self.current_handler = logging.FileHandler(self.current_log_file, encoding='utf-8')
            self.current_handler.setFormatter(
                logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
            )
            logger.addHandler(self.current_handler)

            logger.info(f"📁 日志轮转: 新日志文件 {self.current_log_file} (最大大小: {self.max_size / 1024 / 1024:.1f}MB)")
            self.log_counter += 1

    def check_and_rotate(self):
        """检查文件大小并在需要时轮转"""
        if self._should_rotate():
            self._rotate_log()

    def _cleanup_old_logs(self):
        """清理旧日志文件"""
        cutoff_time = datetime.now() - timedelta(days=self.cleanup_days)
        pattern = str(self.log_dir / "mcpstorewiki_*.log")

        cleaned_count = 0
        for log_file in glob.glob(pattern):
            file_path = Path(log_file)
            if file_path.stat().st_mtime < cutoff_time.timestamp():
                try:
                    file_path.unlink()
                    cleaned_count += 1
                    logger.info(f"🗑️ 清理旧日志: {file_path}")
                except Exception as e:
                    logger.error(f"❌ 清理日志失败 {file_path}: {e}")

        if cleaned_count > 0:
            logger.info(f"🧹 日志清理完成: 删除了 {cleaned_count} 个旧日志文件")
        else:
            logger.info("🧹 日志清理完成: 没有需要清理的文件")

    def _cleanup_worker(self):
        """日志清理工作线程"""
        while True:
            time.sleep(self.cleanup_interval)
            self._cleanup_old_logs()

# 配置基础日志
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.StreamHandler(sys.stdout)
    ]
)

logger = logging.getLogger(__name__)

# 启动日志持久化
log_handler = SizeBasedRotatingLogHandler(LOG_DIR, MAX_LOG_SIZE, LOG_CLEANUP_DAYS, LOG_CLEANUP_INTERVAL)

# 创建 FastMCP 实例
mcp = FastMCP(
    name="WeatherService"
)

# 增强的请求日志记录函数
def log_request_info(endpoint_name, **kwargs):
    """记录详细的请求信息，包括IP、时间和入参"""
    request_time = datetime.now()

    # 获取客户端IP
    client_ip = "unknown"
    try:
        request = get_http_request()
        if request and request.client:
            client_ip = request.client.host

        # 尝试从headers获取真实IP（处理代理情况）
        headers = get_http_headers()
        if headers:
            # 检查常见的代理头
            for header_name in ['X-Forwarded-For', 'X-Real-IP', 'CF-Connecting-IP']:
                if header_name in headers:
                    forwarded_ip = headers[header_name].split(',')[0].strip()
                    if forwarded_ip:
                        client_ip = forwarded_ip
                        break
    except Exception as e:
        logger.debug(f"获取客户端IP失败: {e}")

    # 记录请求开始
    logger.info("=" * 100)
    logger.info(f"🚀 {endpoint_name} 请求开始")
    logger.info(f"⏰ 请求时间: {request_time.isoformat()}")
    logger.info(f"🌐 客户端IP: {client_ip}")

    # 记录入参
    if kwargs:
        logger.info("📋 请求参数:")
        for key, value in kwargs.items():
            # 安全地记录参数，避免敏感信息泄露
            if isinstance(value, str) and len(value) > 1000:
                logger.info(f"   {key}: {value[:1000]}... (截断)")
            else:
                logger.info(f"   {key}: {value}")
    else:
        logger.info("📋 请求参数: 无")

    # 记录HTTP请求详情（如果可用）
    try:
        request = get_http_request()
        if request:
            logger.info(f"🌐 请求URL: {request.url}")
            logger.info(f"📍 请求路径: {request.url.path}")
            logger.info(f"🔧 请求方法: {request.method}")

        headers = get_http_headers()
        if headers:
            logger.info("📨 重要请求头:")
            important_headers = ['User-Agent', 'Content-Type', 'Authorization', 'X-Forwarded-For']
            for header_name in important_headers:
                if header_name in headers:
                    header_value = headers[header_name]
                    # 隐藏敏感信息
                    if 'Authorization' in header_name and header_value:
                        header_value = f"{header_value[:10]}***"
                    logger.info(f"   {header_name}: {header_value}")
    except Exception as e:
        logger.debug(f"获取HTTP请求详情失败: {e}")

    logger.info("=" * 100)

    # 检查日志文件大小并在需要时轮转
    log_handler.check_and_rotate()

    return {
        'timestamp': request_time.isoformat(),
        'client_ip': client_ip,
        'endpoint': endpoint_name,
        'params': kwargs
    }

@mcp.tool()
def get_current_weather(
    query: Annotated[str, Field(description="要查询天气的城市名称，例如：北京、上海、广州")]
) -> str:
    """获取指定城市的当前天气信息，包括温度和天气状况"""
    # 记录详细的请求信息
    request_info = log_request_info("get_current_weather", query=query)

    weather_conditions = ["晴天", "多云", "小雨", "阴天", "雪天"]
    temperature = random.randint(-5, 35)
    condition = random.choice(weather_conditions)
    humidity = random.randint(30, 90)

    result = f"{query}当前天气：{condition}，温度 {temperature}°C，湿度 {humidity}%"

    # 记录结果和请求完成
    end_time = datetime.now()
    logger.info(f"✅ get_current_weather 执行完成")
    logger.info(f"⏰ 完成时间: {end_time.isoformat()}")
    logger.info(f"� 返回结果: {result}")
    logger.info(f"📊 客户端IP: {request_info['client_ip']}")
    logger.info("=" * 100)

    # 检查日志文件大小并在需要时轮转
    log_handler.check_and_rotate()

    return result

@mcp.tool()
def get_weather_forecast(
    city: Annotated[str, Field(description="要查询天气预报的城市名称")],
    days: Annotated[int, Field(default=3, description="预报天数，默认为3天，范围1-7天", ge=1, le=7)]
) -> str:
    """获取指定城市未来几天的天气预报，默认3天"""
    # 记录详细的请求信息
    request_info = log_request_info("get_weather_forecast", city=city, days=days)

    forecast = []
    weather_conditions = ["晴天", "多云", "小雨", "阴天", "雪天"]

    for i in range(days):
        temp = random.randint(-5, 35)
        condition = random.choice(weather_conditions)
        forecast.append(f"第{i+1}天：{condition}，{temp}°C")

    result = f"{city}未来{days}天天气预报：\n" + "\n".join(forecast)

    # 记录结果和请求完成
    end_time = datetime.now()
    logger.info(f"✅ get_weather_forecast 执行完成")
    logger.info(f"⏰ 完成时间: {end_time.isoformat()}")
    logger.info(f"🎯 返回结果: {result}")
    logger.info(f"📊 客户端IP: {request_info['client_ip']}")
    logger.info("=" * 100)

    # 检查日志文件大小并在需要时轮转
    log_handler.check_and_rotate()

    return result

@mcp.tool()
def get_air_quality(
    city: Annotated[str, Field(description="要查询空气质量的城市名称")]
) -> str:
    """获取指定城市的空气质量指数(AQI)信息"""
    # 记录详细的请求信息
    request_info = log_request_info("get_air_quality", city=city)

    aqi_levels = ["优", "良", "轻度污染", "中度污染", "重度污染"]
    aqi_value = random.randint(20, 200)
    level = random.choice(aqi_levels)

    result = f"{city}空气质量：AQI {aqi_value}，等级：{level}"

    # 记录结果和请求完成
    end_time = datetime.now()
    logger.info(f"✅ get_air_quality 执行完成")
    logger.info(f"⏰ 完成时间: {end_time.isoformat()}")
    logger.info(f"🎯 返回结果: {result}")
    logger.info(f"📊 客户端IP: {request_info['client_ip']}")
    logger.info("=" * 100)

    # 检查日志文件大小并在需要时轮转
    log_handler.check_and_rotate()

    return result

# 或者使用文档中推荐的另一种方式（Field 作为默认值）
@mcp.tool()
def search_weather(
    query: str = Field(description="搜索查询字符串，可以是城市名或天气相关关键词"),
    limit: int = Field(10, description="最大返回结果数量", ge=1, le=100)
) -> str:
    """搜索天气相关信息"""
    # 记录详细的请求信息
    request_info = log_request_info("search_weather", query=query, limit=limit)

    result = f"搜索 '{query}' 的前 {limit} 个结果"

    # 记录结果和请求完成
    end_time = datetime.now()
    logger.info(f"✅ search_weather 执行完成")
    logger.info(f"⏰ 完成时间: {end_time.isoformat()}")
    logger.info(f"🎯 返回结果: {result}")
    logger.info(f"📊 客户端IP: {request_info['client_ip']}")
    logger.info("=" * 100)

    # 检查日志文件大小并在需要时轮转
    log_handler.check_and_rotate()

    return result

# 添加一个诊断工具来显示HTTP请求信息
@mcp.tool()
def get_request_info() -> str:
    """获取当前HTTP请求的详细信息，用于诊断反向代理问题"""
    # 记录详细的请求信息
    request_info = log_request_info("get_request_info")

    info_parts = []

    try:
        # 获取请求头信息
        headers = get_http_headers()
        if headers:
            info_parts.append("📨 HTTP 请求头:")
            for name, value in headers.items():
                info_parts.append(f"   {name}: {value}")

        # 获取请求对象
        request = get_http_request()
        if request:
            info_parts.append(f"🌐 请求URL: {request.url}")
            info_parts.append(f"📍 请求路径: {request.url.path}")
            info_parts.append(f"📋 请求方法: {request.method}")
            info_parts.append(f"❓ 查询参数: {dict(request.query_params)}")

            # 客户端信息
            if request.client:
                client_host = getattr(request.client, 'host', 'unknown')
                client_port = getattr(request.client, 'port', 'unknown')
                info_parts.append(f"👤 客户端: {client_host}:{client_port}")

            # 服务器信息
            if hasattr(request, 'url') and request.url:
                info_parts.append(f"🏠 服务器: {request.url.hostname}:{request.url.port}")

        if not info_parts:
            info_parts.append("ℹ️ 当前不在HTTP请求上下文中")

    except Exception as e:
        info_parts.append(f"❌ 获取请求信息失败: {e}")

    result = "\n".join(info_parts)

    # 记录结果和请求完成
    end_time = datetime.now()
    logger.info(f"✅ get_request_info 执行完成")
    logger.info(f"⏰ 完成时间: {end_time.isoformat()}")
    logger.info(f"🎯 返回结果: {result}")
    logger.info(f"📊 客户端IP: {request_info['client_ip']}")
    logger.info("=" * 100)

    # 检查日志文件大小并在需要时轮转
    log_handler.check_and_rotate()

    return result

if __name__ == "__main__":
    logger.info("🚀 启动天气服务器...")
    logger.info("=" * 100)
    logger.info("📋 服务器配置信息:")
    logger.info("   🌐 传输协议: streamable-http")
    logger.info("   🏠 监听地址: 0.0.0.0")
    logger.info("   🔌 监听端口: 21923")
    logger.info("   📍 服务路径: /mcp")
    logger.info("   🌍 完整地址: http://0.0.0.0:21923/mcp")
    logger.info("=" * 100)

    logger.info("📁 日志持久化配置:")
    logger.info(f"   📂 日志目录: {LOG_DIR.absolute()}")
    logger.info(f"   📏 文件大小限制: {MAX_LOG_SIZE / 1024 / 1024:.1f}MB")
    logger.info(f"   🔄 轮转方式: 基于文件大小自动轮转")
    logger.info(f"   🗑️ 清理周期: {LOG_CLEANUP_DAYS}天")
    logger.info(f"   🔄 清理检查: 每{LOG_CLEANUP_INTERVAL}秒 (每天)")
    logger.info("   📊 记录内容: IP地址、时间戳、请求参数、响应结果")
    logger.info("=" * 100)

    # 添加一些针对反向代理的提示
    logger.info("🔧 反向代理配置提示:")
    logger.info("   📝 nginx 配置示例:")
    logger.info("   location /mcp {")
    logger.info("       proxy_pass http://127.0.0.1:21923/mcp;")
    logger.info("       proxy_set_header Host $host;")
    logger.info("       proxy_set_header X-Real-IP $remote_addr;")
    logger.info("       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;")
    logger.info("       proxy_set_header X-Forwarded-Proto $scheme;")
    logger.info("       proxy_http_version 1.1;")
    logger.info("       proxy_set_header Upgrade $http_upgrade;")
    logger.info("       proxy_set_header Connection 'upgrade';")
    logger.info("       proxy_cache_bypass $http_upgrade;")
    logger.info("       proxy_read_timeout 86400;")
    logger.info("   }")
    logger.info("=" * 80)

    try:
        logger.info("🎯 开始启动服务...")
        mcp.run(
            transport="streamable-http",
            host="0.0.0.0",
            port=21923,
            path="/"  # 改为根路径，配合 nginx 的 proxy_pass
        )
    except Exception as e:
        logger.error(f"❌ 服务启动失败: {e}")
        logger.error(f"💥 错误类型: {type(e).__name__}")
        import traceback
        logger.error(f"📍 错误堆栈:\n{traceback.format_exc()}")
        raise
