#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
LSP WebSocket API路由
为脚本编辑器提供基于WebSocket的Language Server Protocol支持
"""

import json
import asyncio
from typing import Dict, Any, Optional
from fastapi import WebSocket, WebSocketDisconnect, APIRouter
from utils.logger import get_logger
from services.online_script.lsp_completion_service import get_lsp_completion_service

logger = get_logger("routes.lsp_websocket")
router = APIRouter(prefix="/lsp", tags=["LSP WebSocket"])


class LSPConnectionManager:
    """LSP WebSocket连接管理器"""
    
    def __init__(self):
        self.active_connections: Dict[str, Dict[str, Any]] = {}
        self.lsp_service = get_lsp_completion_service()
        
    async def connect(self, websocket: WebSocket, client_id: str):
        """建立WebSocket连接"""
        await websocket.accept()
        self.active_connections[client_id] = {
            'websocket': websocket,
            'documents': {},  # 存储文档状态
            'initialized': False
        }
        logger.info(f"LSP客户端连接: {client_id}")
        
    def disconnect(self, client_id: str):
        """断开WebSocket连接"""
        if client_id in self.active_connections:
            del self.active_connections[client_id]
            logger.info(f"LSP客户端断开: {client_id}")
    
    async def send_message(self, client_id: str, message: Dict[str, Any]):
        """发送消息给指定客户端"""
        if client_id in self.active_connections:
            websocket = self.active_connections[client_id]['websocket']
            try:
                await websocket.send_text(json.dumps(message, ensure_ascii=False))
            except Exception as e:
                logger.error(f"发送LSP消息失败 {client_id}: {e}")
                self.disconnect(client_id)
    
    async def handle_message(self, client_id: str, message: Dict[str, Any]) -> Optional[Dict[str, Any]]:
        """处理LSP消息"""
        try:
            method = message.get('method')
            params = message.get('params', {})
            
            # 更新文档状态
            if method == 'textDocument/didOpen':
                await self._handle_did_open(client_id, params)
                logger.info(f"客户端 {client_id} 打开文档")
            elif method == 'textDocument/didChange':
                await self._handle_did_change(client_id, params)
            elif method == 'textDocument/didClose':
                await self._handle_did_close(client_id, params)

            # 为需要文档内容的请求添加文档文本
            if method in ['textDocument/completion', 'textDocument/signatureHelp', 'textDocument/hover']:
                text_document = params.get('textDocument', {})
                uri = text_document.get('uri')

                logger.debug(f"处理 {method} 请求, URI: {uri}, 客户端: {client_id}")

                if uri and client_id in self.active_connections:
                    documents = self.active_connections[client_id]['documents']
                    logger.debug(f"当前文档列表: {list(documents.keys())}")

                    if uri in documents:
                        # 将文档内容添加到context中
                        if 'context' not in params:
                            params['context'] = {}
                        params['context']['documentText'] = documents[uri]['text']
                        message['params'] = params
                        logger.debug(f"已添加文档内容，长度: {len(documents[uri]['text'])}")
                    else:
                        logger.warning(f"未找到文档 {uri}，当前已打开文档: {list(documents.keys())}")
                        # 提供空文档内容，避免补全完全失败
                        if 'context' not in params:
                            params['context'] = {}
                        params['context']['documentText'] = ''
                        message['params'] = params
                else:
                    logger.warning(f"客户端 {client_id} 不存在或URI为空")
            
            # 使用LSP服务处理消息
            response = self.lsp_service.handle_lsp_message(message)
            return response
            
        except Exception as e:
            logger.error(f"处理LSP消息失败 {client_id}: {e}", exc_info=True)
            return {
                "jsonrpc": "2.0",
                "id": message.get('id'),
                "error": {
                    "code": -32603,
                    "message": f"Internal error: {str(e)}"
                }
            }
    
    async def _handle_did_open(self, client_id: str, params: Dict[str, Any]):
        """处理文档打开"""
        text_document = params.get('textDocument', {})
        uri = text_document.get('uri')
        text = text_document.get('text', '')
        version = text_document.get('version', 1)
        
        if uri and client_id in self.active_connections:
            self.active_connections[client_id]['documents'][uri] = {
                'text': text,
                'version': version
            }
            logger.debug(f"文档已打开: {uri}")
    
    async def _handle_did_change(self, client_id: str, params: Dict[str, Any]):
        """处理文档变更"""
        text_document = params.get('textDocument', {})
        uri = text_document.get('uri')
        version = text_document.get('version')
        content_changes = params.get('contentChanges', [])

        if uri and client_id in self.active_connections:
            documents = self.active_connections[client_id]['documents']

            if uri in documents:
                # 应用文档变更
                for change in content_changes:
                    if 'range' not in change:
                        # 全文更新
                        documents[uri]['text'] = change.get('text', '')
                        logger.debug(f"全文更新: {uri}")
                    else:
                        # 增量更新 - 正确实现
                        documents[uri]['text'] = self._apply_text_edit(
                            documents[uri]['text'],
                            change.get('range'),
                            change.get('text', '')
                        )
                        logger.debug(f"增量更新: {uri}, range: {change.get('range')}, text: {change.get('text', '')}")

                documents[uri]['version'] = version
                logger.debug(f"文档已更新: {uri}, 版本: {version}, 内容预览: {documents[uri]['text'][:100]}")
    
    async def _handle_did_close(self, client_id: str, params: Dict[str, Any]):
        """处理文档关闭"""
        text_document = params.get('textDocument', {})
        uri = text_document.get('uri')

        if uri and client_id in self.active_connections:
            documents = self.active_connections[client_id]['documents']
            if uri in documents:
                del documents[uri]
                logger.debug(f"文档已关闭: {uri}")

    def _apply_text_edit(self, text: str, range_info: Dict[str, Any], new_text: str) -> str:
        """
        应用文本编辑到文档

        Args:
            text: 原始文档文本
            range_info: LSP Range对象，包含start和end位置
            new_text: 要插入的新文本

        Returns:
            更新后的文档文本
        """
        if not range_info:
            return new_text

        start = range_info.get('start', {})
        end = range_info.get('end', {})
        start_line = start.get('line', 0)
        start_char = start.get('character', 0)
        end_line = end.get('line', 0)
        end_char = end.get('character', 0)

        # 将文档分割成行
        lines = text.split('\n')

        # 确保行数足够
        while len(lines) <= max(start_line, end_line):
            lines.append('')

        # 获取起始行和结束行
        start_line_text = lines[start_line] if start_line < len(lines) else ''
        end_line_text = lines[end_line] if end_line < len(lines) else ''

        # 构建新的文本
        # 保留起始行的前半部分
        before = start_line_text[:start_char]
        # 保留结束行的后半部分
        after = end_line_text[end_char:]
        # 新文本
        new_content = before + new_text + after

        # 构建新的行数组
        if start_line == end_line:
            # 单行编辑
            lines[start_line] = new_content
        else:
            # 多行编辑
            new_lines = new_content.split('\n')
            lines = lines[:start_line] + new_lines + lines[end_line + 1:]

        return '\n'.join(lines)


# 全局连接管理器
lsp_manager = LSPConnectionManager()


@router.websocket("/code-completion/{client_id}")
async def lsp_websocket_endpoint(websocket: WebSocket, client_id: str):
    """LSP WebSocket端点"""
    await lsp_manager.connect(websocket, client_id)
    
    try:
        while True:
            # 接收消息
            data = await websocket.receive_text()
            
            try:
                message = json.loads(data)
                logger.debug(f"接收到LSP消息 {client_id}: {message.get('method', 'unknown')}")
                
                # 处理消息
                response = await lsp_manager.handle_message(client_id, message)
                
                # 发送响应
                if response:
                    await lsp_manager.send_message(client_id, response)
                    
            except json.JSONDecodeError as e:
                logger.error(f"JSON解析失败 {client_id}: {e}")
                error_response = {
                    "jsonrpc": "2.0",
                    "id": None,
                    "error": {
                        "code": -32700,
                        "message": "Parse error"
                    }
                }
                await lsp_manager.send_message(client_id, error_response)
                
            except Exception as e:
                logger.error(f"处理消息失败 {client_id}: {e}", exc_info=True)
                
    except WebSocketDisconnect:
        logger.info(f"LSP客户端断开连接: {client_id}")
    except Exception as e:
        logger.error(f"WebSocket连接异常 {client_id}: {e}")
    finally:
        lsp_manager.disconnect(client_id)


@router.get("/health")
async def lsp_health_check():
    """LSP服务健康检查"""
    return {
        "status": "healthy",
        "service": "VWED LSP Code Completion",
        "active_connections": len(lsp_manager.active_connections),
        "capabilities": [
            "textDocument/completion",
            "textDocument/signatureHelp", 
            "textDocument/hover",
            "textDocument/didOpen",
            "textDocument/didChange",
            "textDocument/didClose"
        ]
    }


@router.get("/clients")
async def get_active_clients():
    """获取活跃的LSP客户端"""
    clients = []
    for client_id, connection in lsp_manager.active_connections.items():
        clients.append({
            "client_id": client_id,
            "initialized": connection.get('initialized', False),
            "document_count": len(connection.get('documents', {})),
            "documents": list(connection.get('documents', {}).keys())
        })
    
    return {
        "active_clients": clients,
        "total_count": len(clients)
    }