package client

import (
	"context"
	"encoding/json"
	"strings"

	"github.com/keepmind9/acp-sdk-go/rpc"
	"github.com/keepmind9/acp-sdk-go/schema"
)

// buildClientRouter creates a rpc.Handler that dispatches incoming JSON-RPC
// messages to the appropriate Client interface method.
func buildClientRouter(client Client) rpc.Handler {
	return func(method string, params json.RawMessage, isRequest bool) (any, error) {
		ctx := context.Background()

		// Extension methods start with "_"
		if strings.HasPrefix(method, "_") {
			return handleClientExtension(client, ctx, method, params, isRequest)
		}

		switch method {
		case schema.MethodSessionUpdate:
			// Notification
			if isRequest {
				return nil, nil
			}
			var notif schema.SessionNotification
			if err := json.Unmarshal(params, &notif); err != nil {
				return nil, nil
			}
			client.SessionUpdate(ctx, &notif)
			return nil, nil

		case schema.MethodSessionRequest_permission:
			if !isRequest {
				return nil, nil
			}
			var req schema.RequestPermissionRequest
			if err := json.Unmarshal(params, &req); err != nil {
				return nil, rpc.NewRPCError(-32602, "Invalid params: "+err.Error())
			}
			return client.RequestPermission(ctx, &req)

		case schema.MethodFsRead_text_file:
			if !isRequest {
				return nil, nil
			}
			var req schema.ReadTextFileRequest
			if err := json.Unmarshal(params, &req); err != nil {
				return nil, rpc.NewRPCError(-32602, "Invalid params: "+err.Error())
			}
			return client.ReadTextFile(ctx, &req)

		case schema.MethodFsWrite_text_file:
			if !isRequest {
				return nil, nil
			}
			var req schema.WriteTextFileRequest
			if err := json.Unmarshal(params, &req); err != nil {
				return nil, rpc.NewRPCError(-32602, "Invalid params: "+err.Error())
			}
			return client.WriteTextFile(ctx, &req)

		case schema.MethodTerminalCreate:
			if !isRequest {
				return nil, nil
			}
			var req schema.CreateTerminalRequest
			if err := json.Unmarshal(params, &req); err != nil {
				return nil, rpc.NewRPCError(-32602, "Invalid params: "+err.Error())
			}
			return client.CreateTerminal(ctx, &req)

		case schema.MethodTerminalOutput:
			if !isRequest {
				return nil, nil
			}
			var req schema.TerminalOutputRequest
			if err := json.Unmarshal(params, &req); err != nil {
				return nil, rpc.NewRPCError(-32602, "Invalid params: "+err.Error())
			}
			return client.TerminalOutput(ctx, &req)

		case schema.MethodTerminalRelease:
			if !isRequest {
				return nil, nil
			}
			var req schema.ReleaseTerminalRequest
			if err := json.Unmarshal(params, &req); err != nil {
				return nil, rpc.NewRPCError(-32602, "Invalid params: "+err.Error())
			}
			return client.ReleaseTerminal(ctx, &req)

		case schema.MethodTerminalWait_for_exit:
			if !isRequest {
				return nil, nil
			}
			var req schema.WaitForTerminalExitRequest
			if err := json.Unmarshal(params, &req); err != nil {
				return nil, rpc.NewRPCError(-32602, "Invalid params: "+err.Error())
			}
			return client.WaitForTerminalExit(ctx, &req)

		case schema.MethodTerminalKill:
			if !isRequest {
				return nil, nil
			}
			var req schema.KillTerminalRequest
			if err := json.Unmarshal(params, &req); err != nil {
				return nil, rpc.NewRPCError(-32602, "Invalid params: "+err.Error())
			}
			return client.KillTerminal(ctx, &req)

		default:
			if isRequest {
				return nil, rpc.NewRPCError(-32601, "Method not found: "+method)
			}
			return nil, nil
		}
	}
}

// handleClientExtension dispatches extension methods (starting with "_").
func handleClientExtension(client Client, ctx context.Context, method string, params json.RawMessage, isRequest bool) (any, error) {
	var p map[string]any
	if params != nil {
		json.Unmarshal(params, &p)
	}

	if isRequest {
		if h, ok := client.(ExtMethodHandler); ok {
			return h.ExtMethod(ctx, method, p)
		}
		return nil, rpc.NewRPCError(-32601, "Method not found: "+method)
	}

	if h, ok := client.(ExtNotificationHandler); ok {
		h.ExtNotification(ctx, method, p)
	}
	return nil, nil
}
