// Author: NiuJiuRu
// Email: niujiuru@qq.com

package jsonrpc2

import (
	"encoding/json"
	"errors"
	"fmt"
)

type ErrCode int

const (
	ErrParse          ErrCode = -32700 // "Parse error"
	ErrInvalidRequest ErrCode = -32600 // "Invalid request"
	ErrMethodNotFound ErrCode = -32601 // "Method not found"
	ErrInvalidParams  ErrCode = -32602 // "Invalid params"
	ErrInternal       ErrCode = -32603 // "Internal error"
)

type Error struct {
	Code    ErrCode `json:"code"`    //// 错误码
	Message string  `json:"message"` //// 错误信息
}

func (e Error) Error() string {
	return e.Message
}

var errMessages = map[ErrCode]string{
	ErrParse:          "Parse error",      // 解析错误
	ErrInvalidRequest: "Invalid request",  // 无效请求
	ErrMethodNotFound: "Method not found", // 无效方法
	ErrInvalidParams:  "Invalid params",   // 无效参数
	ErrInternal:       "Internal error",   // 内部错误
}

type Request struct {
	JSONRPC string          `json:"jsonrpc"`          // 版本号, 固定: "2.0"
	Method  string          `json:"method"`           // 调用方法, 执行函数名
	Params  json.RawMessage `json:"params,omitempty"` // 请求参数, 可选可为空
	ID      *int64          `json:"id,omitempty"`     // 请求ID, 用于标识请求
}

type Response struct {
	JSONRPC string          `json:"jsonrpc"`          // 版本号, 固定: "2.0"
	Result  json.RawMessage `json:"result,omitempty"` // 响应结果, 可选可为空
	Error   *Error          `json:"error,omitempty"`  // 错误信息, 可选可为空
	ID      *int64          `json:"id"`               // 应答ID, 响应匹配请求
}

// 解析请求数据
func ParseRequest(input any) (*Request, error) {
	var raw []byte

	switch v := input.(type) {
	case nil:
		return nil, errors.New("request data is nil")
	case string:
		raw = []byte(v)
	case []byte:
		raw = v
	default:
		return nil, errors.New("unsupported request data type: must be string or []byte")
	}

	var req Request
	if err := json.Unmarshal(raw, &req); err != nil {
		return nil, fmt.Errorf("unmarshal request: %w", err)
	}

	if req.JSONRPC != "2.0" {
		return nil, errors.New("invalid JSON-RPC version")
	}

	if req.Method == "" {
		return nil, errors.New("method cannot be empty")
	}

	return &req, nil
}

// 解析应答数据
func ParseResponse(input any) (*Response, error) {
	var raw []byte

	switch v := input.(type) {
	case nil:
		return nil, errors.New("response data is nil")
	case string:
		raw = []byte(v)
	case []byte:
		raw = v
	default:
		return nil, errors.New("unsupported response data type: must be string or []byte")
	}

	var resp Response
	if err := json.Unmarshal(raw, &resp); err != nil {
		return nil, fmt.Errorf("unmarshal response: %w", err)
	}

	if resp.JSONRPC != "2.0" {
		return nil, errors.New("invalid JSON-RPC version")
	}

	// 情况 1：result 和 error 同时为空 → 错误
	if resp.Error == nil && resp.Result == nil {
		return nil, errors.New(`response must contain either "result" or "error" field`)
	}

	// 情况 2：result 和 error 同时存在 → 错误
	if resp.Error != nil && resp.Result != nil {
		return nil, errors.New(`response can't contain both "result" and "error" field`)
	}

	// 情况 3：成功时的应答 → 必须有id&且不能空
	if resp.Result != nil {
		if resp.ID == nil {
			return nil, errors.New(`"id" must exist and cannot be null for successful response`)
		}
		return &resp, nil
	}

	// 情况 4：错误时的应答 → 必须有id&且不能空
	if resp.Error != nil && resp.Error.Code == ErrParse { // 当发生解析错误时, "id"必须为: nil
		/*if resp.ID != nil { // 虽然更符合规范, 但编程时有的应答会返回ErrParse, 为了兼容, 暂不启用
			return nil, errors.New(`"id" must be null for parse error`)
		}*/
		return &resp, nil
	}

	if resp.ID == nil {
		return nil, errors.New(`"id" must exist and cannot be null for error response`)
	}

	return &resp, nil
}

// 编码JSON数据
func marshalJSON(input any) (json.RawMessage, error) {
	switch v := input.(type) {
	case nil:
		return nil, nil
	case []byte:
		return nil, errors.New("[]byte is not allowed: use json.RawMessage for raw JSON")
	case json.RawMessage:
		return v, nil
	default:
		b, err := json.Marshal(v)
		if err != nil {
			return nil, fmt.Errorf("marshal json: %w", err)
		}
		return json.RawMessage(b), nil
	}
}

// 构建一个请求
func BuildRequest(method string, params any, id ...int64) (*Request, error) {
	if method == "" {
		return nil, errors.New("method cannot be empty")
	}

	raw, err := marshalJSON(params)
	if err != nil {
		return nil, err
	}

	var rid int64
	if len(id) > 0 {
		rid = id[0]
	} else {
		rid = nextID()
	}

	req := &Request{
		JSONRPC: "2.0",
		Method:  method,
		ID:      &rid,
	}

	if raw != nil { // 非空参数
		req.Params = raw
	}

	return req, nil
}

// 构建一个通知
func BuildNotification(method string, params any) (*Request, error) {
	if method == "" {
		return nil, errors.New("method cannot be empty")
	}

	raw, err := marshalJSON(params)
	if err != nil {
		return nil, err
	}

	req := &Request{
		JSONRPC: "2.0",
		Method:  method,
	}

	if raw != nil { // 非空参数
		req.Params = raw
	}

	return req, nil
}

// 构建成功应答
func BuildResult(req *Request, result any) (*Response, error) {
	if req.ID == nil { // 通知类型, 不用应答
		return nil, nil
	}

	raw, err := marshalJSON(result)
	if err != nil {
		return nil, err
	}

	if raw == nil {
		raw = json.RawMessage("null")
	}

	return &Response{
		JSONRPC: "2.0",
		Result:  raw,
		ID:      req.ID,
	}, nil
}

// 构建错误应答
func BuildError(req *Request, code ErrCode, message string) *Response {
	id := (*int64)(nil)

	if req != nil {
		id = req.ID
	}

	/*if code == ErrParse {
		id = nil
	}*/ // 虽然更符合规范, 但编程时code可能会使用ErrParse, 为了兼容, 暂不启用

	emsg := message
	if emsg == "" {
		emsg = errMessages[code]
	}

	return &Response{
		JSONRPC: "2.0",
		Error: &Error{
			Code:    code,
			Message: emsg,
		},
		ID: id,
	}
}

// 构建一个应答
// 有错误时, result会被忽略; 没有错误时, error会被忽略
func BuildResponse(req *Request, result any, err error) *Response {
	if err != nil {
		return BuildError(req, ErrInternal, err.Error())
	}

	resp, err := BuildResult(req, result)
	if err != nil {
		return BuildError(req, ErrInternal, "")
	}

	return resp
}

// 是否通知消息
func (req *Request) IsNotification() bool {
	return req.ID == nil
}

// 请求转字符串
func (req *Request) String() (string, error) {
	b, err := json.Marshal(req)
	if err != nil {
		return "", fmt.Errorf("marshal request: %w", err)
	}
	return string(b), nil
}

// 应答转字符串
func (resp *Response) String() (string, error) {
	b, err := json.Marshal(resp)
	if err != nil {
		return "", fmt.Errorf("marshal response: %w", err)
	}
	return string(b), nil
}
