package handler

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"mcp-bridge/src/logger"

	"github.com/creachadair/jrpc2"
)

// RPCClient defines the interface for a JSON-RPC client
type RPCClient interface {
	CallResult(ctx context.Context, method string, params interface{}, result interface{}) error
	Close() error
}

// ServiceHandler manages HTTP requests for a specific service
type ServiceHandler struct {
	Client      RPCClient
	ServiceName string
	Path        string
	McpMethod   string
	ToolName    string
}

// NewServiceHandler creates a new ServiceHandler
func NewServiceHandler(client RPCClient, serviceName, path, mcpMethod, toolName string) *ServiceHandler {
	return &ServiceHandler{
		Client:      client,
		ServiceName: serviceName,
		Path:        path,
		McpMethod:   mcpMethod,
		ToolName:    toolName,
	}
}

// ServeHTTP handles HTTP requests for the service
func (h *ServiceHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	reqLogger := logger.WithFields(logger.Fields{
		"path":       h.Path,
		"service":    h.ServiceName,
		"method":     r.Method,
		"remote_ip":  r.RemoteAddr,
		"user_agent": r.UserAgent(),
		"request_id": r.Header.Get("X-Request-ID"),
	})
	reqLogger.Info("Handling request")

	// Check if the client is available
	if h.Client == nil {
		reqLogger.Error("Service client is nil")
		http.Error(w, fmt.Sprintf("Service %s not found", h.ServiceName), http.StatusInternalServerError)
		return
	}

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		reqLogger.WithFields(logger.Fields{
			"error": err,
		}).Error("Error reading request body")
		http.Error(w, "Error reading request body", http.StatusInternalServerError)
		return
	}
	defer r.Body.Close()

	var params json.RawMessage
	if len(body) > 0 {
		if err := json.Unmarshal(body, &params); err != nil {
			reqLogger.WithFields(logger.Fields{
				"error": err,
			}).Error("Error parsing JSON body")
			http.Error(w, "Error parsing JSON body", http.StatusBadRequest)
			return
		}
	}

	// Call the adapter
	var result json.RawMessage
	ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
	defer cancel()

	startTime := time.Now()
	if err := h.Client.CallResult(ctx, h.McpMethod, params, &result); err != nil {
		reqLogger.WithFields(logger.Fields{
			"error":       err,
			"duration_ms": time.Since(startTime).Milliseconds(),
		}).Error("RPC call failed")

		// Check for JSON-RPC specific errors
		if jrpcErr, ok := err.(*jrpc2.Error); ok {
			w.WriteHeader(http.StatusBadRequest)
			json.NewEncoder(w).Encode(jrpcErr)
		} else {
			http.Error(w, fmt.Sprintf("RPC call failed: %v", err), http.StatusInternalServerError)
		}
		return
	}

	reqLogger.WithFields(logger.Fields{
		"duration_ms": time.Since(startTime).Milliseconds(),
	}).Info("Request completed successfully")

	// Write the successful response back
	w.Header().Set("Content-Type", "application/json")
	w.Write(result)
}

// ReloadHandler handles HTTP requests to reload the configuration
type ReloadHandler struct {
	ReloadFunc func() error
}

// NewReloadHandler creates a new ReloadHandler
func NewReloadHandler(reloadFunc func() error) *ReloadHandler {
	return &ReloadHandler{
		ReloadFunc: reloadFunc,
	}
}

// ServeHTTP handles HTTP requests for configuration reload
func (h *ReloadHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	logger.Info("Received reload request via HTTP endpoint")

	if err := h.ReloadFunc(); err != nil {
		logger.WithFields(logger.Fields{
			"error": err,
		}).Error("Failed to reload configuration")
		http.Error(w, fmt.Sprintf("Failed to reload: %v", err), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusAccepted)
	w.Write([]byte(`{"status":"reload initiated"}`))
}
