#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
JSON-RPC Communication Module
JSON-RPC 通信模块

Provides standardized JSON-RPC 2.0 communication for Tauri-Python integration.
"""

import json
import sys
import time
from typing import Any, Dict, Optional, Union


class JSONRPCResponse:
    """JSON-RPC 2.0 Response handler"""
    
    def __init__(self, request_id: Optional[Union[str, int]] = None):
        self.request_id = request_id
    
    def success(self, result: Any) -> None:
        """Send successful response"""
        response = {
            "jsonrpc": "2.0",
            "id": self.request_id,
            "result": result
        }
        self._send_response(response)
    
    def error(self, code: int, message: str, data: Any = None) -> None:
        """Send error response"""
        error_obj = {
            "code": code,
            "message": message
        }
        if data is not None:
            error_obj["data"] = data
            
        response = {
            "jsonrpc": "2.0",
            "id": self.request_id,
            "error": error_obj
        }
        self._send_response(response)
    
    def notification(self, method: str, params: Any = None) -> None:
        """Send notification (no response expected)"""
        notification = {
            "jsonrpc": "2.0",
            "method": method,
            "params": params
        }
        self._send_response(notification)
    
    def _send_response(self, response: Dict[str, Any]) -> None:
        """Send JSON-RPC response to stdout with proper encoding"""
        try:
            # Use ensure_ascii=True to avoid Unicode encoding issues
            json_str = json.dumps(response, ensure_ascii=True, separators=(',', ':'))

            # Ensure stdout is properly configured for UTF-8
            output_line = f"JSONRPC:{json_str}"

            # Write to stdout with explicit encoding handling
            if hasattr(sys.stdout, 'buffer'):
                # Python 3: write bytes to buffer to ensure proper encoding
                sys.stdout.buffer.write(output_line.encode('utf-8'))
                sys.stdout.buffer.write(b'\n')
                sys.stdout.buffer.flush()
            else:
                # Fallback for older Python versions
                print(output_line)
                sys.stdout.flush()

        except Exception as e:
            # Fallback error response with safe encoding
            try:
                fallback = {
                    "jsonrpc": "2.0",
                    "id": self.request_id,
                    "error": {
                        "code": -32603,
                        "message": "Internal error",
                        "data": str(e)
                    }
                }
                fallback_json = json.dumps(fallback, ensure_ascii=True)
                fallback_line = f"JSONRPC:{fallback_json}"

                if hasattr(sys.stdout, 'buffer'):
                    sys.stdout.buffer.write(fallback_line.encode('utf-8'))
                    sys.stdout.buffer.write(b'\n')
                    sys.stdout.buffer.flush()
                else:
                    print(fallback_line)
                    sys.stdout.flush()
            except Exception as fallback_error:
                # Last resort: simple error message
                error_msg = f"JSONRPC:{{\"jsonrpc\":\"2.0\",\"id\":{self.request_id},\"error\":{{\"code\":-32603,\"message\":\"Encoding error\"}}}}"
                try:
                    if hasattr(sys.stdout, 'buffer'):
                        sys.stdout.buffer.write(error_msg.encode('utf-8'))
                        sys.stdout.buffer.write(b'\n')
                        sys.stdout.buffer.flush()
                    else:
                        print(error_msg)
                        sys.stdout.flush()
                except:
                    pass  # Give up if even this fails


class ProgressReporter:
    """Progress reporting using JSON-RPC notifications"""
    step: int = 0
    total: int = 0
    def __init__(self, total: int = 0):
        self.rpc = JSONRPCResponse()
    
    def report(self, step: str, progress: float, message: str, details: Dict[str, Any] = None) -> None:
        """Report progress using JSON-RPC notification"""
        params = {
            "step": step,
            "progress": progress,  # 0.0 to 1.0
            "message": message,
            "timestamp": time.time()
        }
        if details:
            params["details"] = details
            
        self.rpc.notification("progress", params)
    
    def step(self, step_name: str, message: str) -> None:
        """Report a step without specific progress"""
        self.report(step_name, -1, message)
    
    def complete(self, message: str = "完成") -> None:
        """Report completion"""
        self.report("complete", 1.0, message)
        
    def update(self, step: str, progress: float, message: str, details: Dict[str, Any] = None) -> None:
        self.report(step=step, progress=progress,message=message,details=details)
    
    def error(self, message: str, error_details: Dict[str, Any] = None) -> None:
        """Report error"""
        self.report("error", -1, message, error_details)

    def info(self, message: str) -> None:
        """Report info message"""
        self.report("info", -1, message)

    def success(self, message: str) -> None:
        """Report success message"""
        self.report("success", -1, message)

    def warning(self, message: str) -> None:
        """Report warning message"""
        self.report("warning", -1, message)


# Error codes following JSON-RPC 2.0 specification
class JSONRPCError:
    PARSE_ERROR = -32700
    INVALID_REQUEST = -32600
    METHOD_NOT_FOUND = -32601
    INVALID_PARAMS = -32602
    INTERNAL_ERROR = -32603
    
    # Custom application errors (start from -32000)
    FILE_NOT_FOUND = -32001
    UPLOAD_FAILED = -32002
    GENERATION_FAILED = -32003
    DOWNLOAD_FAILED = -32004
    TIMEOUT_ERROR = -32005
    TEMPLATE_IMPORT_FAILED = -32006
    TEMPLATE_NOT_FOUND = -32007


def create_response_handler(request_id: Optional[Union[str, int]] = None) -> JSONRPCResponse:
    """Create a JSON-RPC response handler"""
    return JSONRPCResponse(request_id)


def create_progress_reporter() -> ProgressReporter:
    """Create a progress reporter"""
    return ProgressReporter()


def parse_request(request_str: str) -> Dict[str, Any]:
    """Parse JSON-RPC request string"""
    try:
        request = json.loads(request_str)
        if not isinstance(request, dict):
            raise ValueError("Request must be a JSON object")
        
        # Validate JSON-RPC 2.0 format
        if request.get("jsonrpc") != "2.0":
            raise ValueError("Invalid JSON-RPC version")
        
        if "method" not in request:
            raise ValueError("Missing method field")
        
        return request
    except json.JSONDecodeError as e:
        raise ValueError(f"Invalid JSON: {e}")

