/*
 * Copyright 2022 CloudWeGo Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package gonet

import (
	"context"
	"net"
	"time"

	"github.com/cloudwego/gopkg/bufiox"
	"github.com/cloudwego/netpoll"

	"github.com/cloudwego/kitex/internal/mocks"
	"github.com/cloudwego/kitex/pkg/remote"
)

type MockCodec struct {
	EncodeFunc func(ctx context.Context, msg remote.Message, out remote.ByteBuffer) error
	DecodeFunc func(ctx context.Context, msg remote.Message, in remote.ByteBuffer) error
}

func (m *MockCodec) Name() string {
	return "Mock"
}

func (m *MockCodec) Encode(ctx context.Context, msg remote.Message, out remote.ByteBuffer) (err error) {
	if m.EncodeFunc != nil {
		return m.EncodeFunc(ctx, msg, out)
	}
	return
}

func (m *MockCodec) Decode(ctx context.Context, msg remote.Message, in remote.ByteBuffer) (err error) {
	if m.DecodeFunc != nil {
		return m.DecodeFunc(ctx, msg, in)
	}
	return
}

var (
	_ net.Conn         = &MockNetConn{}
	_ bufioxReadWriter = &MockNetConn{}
)

// MockNetConn implements net.Conn.
type MockNetConn struct {
	mocks.Conn
	r                  *bufiox.DefaultReader
	w                  *bufiox.DefaultWriter
	IsActiveFunc       func() (r bool)
	SetIdleTimeoutFunc func(timeout time.Duration) (e error)
	SetOnRequestFunc   func(on netpoll.OnRequest) (e error)
	SetReadTimeoutFunc func(timeout time.Duration) (e error)
}

func newMockNetConn(conn net.Conn) *MockNetConn {
	return &MockNetConn{
		Conn: conn.(mocks.Conn),
		r:    bufiox.NewDefaultReader(conn),
		w:    bufiox.NewDefaultWriter(conn),
	}
}

// IsActive implements the netpoll.Connection interface.
func (m *MockNetConn) IsActive() (r bool) {
	if m.IsActiveFunc != nil {
		return m.IsActiveFunc()
	}
	return
}

// Reader implements the netpoll.Connection interface.
func (m *MockNetConn) Reader() (r *bufiox.DefaultReader) {
	return m.r
}

// Writer implements the netpoll.Connection interface.
func (m *MockNetConn) Writer() (r *bufiox.DefaultWriter) {
	return m.w
}

// SetIdleTimeout implements the netpoll.Connection interface.
func (m *MockNetConn) SetIdleTimeout(timeout time.Duration) (e error) {
	if m.SetIdleTimeoutFunc != nil {
		return m.SetIdleTimeoutFunc(timeout)
	}
	return
}

// SetOnRequest implements the netpoll.Connection interface.
func (m *MockNetConn) SetOnRequest(on netpoll.OnRequest) (e error) {
	if m.SetOnRequestFunc != nil {
		return m.SetOnRequestFunc(on)
	}
	return
}

// SetReadTimeout implements the netpoll.Connection interface.
func (m *MockNetConn) SetReadTimeout(timeout time.Duration) (e error) {
	if m.SetReadTimeoutFunc != nil {
		return m.SetReadTimeoutFunc(timeout)
	}
	return
}
