/*
 * Copyright 2021 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 mocks

import (
	bytes2 "bytes"
	"net"
	"time"

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

var _ net.Conn = &Conn{}

// Conn implements the net.Conn interface.
type Conn struct {
	ReadFunc             func(b []byte) (n int, err error)
	WriteFunc            func(b []byte) (n int, err error)
	CloseFunc            func() (e error)
	LocalAddrFunc        func() (r net.Addr)
	RemoteAddrFunc       func() (r net.Addr)
	SetDeadlineFunc      func(t time.Time) (e error)
	SetReadDeadlineFunc  func(t time.Time) (e error)
	SetWriteDeadlineFunc func(t time.Time) (e error)
}

// Read implements the net.Conn interface.
func (m Conn) Read(b []byte) (n int, err error) {
	if m.ReadFunc != nil {
		return m.ReadFunc(b)
	}
	return
}

// Write implements the net.Conn interface.
func (m Conn) Write(b []byte) (n int, err error) {
	if m.WriteFunc != nil {
		return m.WriteFunc(b)
	}
	return
}

// Close implements the net.Conn interface.
func (m Conn) Close() (e error) {
	if m.CloseFunc != nil {
		return m.CloseFunc()
	}
	return
}

// LocalAddr implements the net.Conn interface.
func (m Conn) LocalAddr() (r net.Addr) {
	if m.LocalAddrFunc != nil {
		return m.LocalAddrFunc()
	}
	return
}

// RemoteAddr implements the net.Conn interface.
func (m Conn) RemoteAddr() (r net.Addr) {
	if m.RemoteAddrFunc != nil {
		return m.RemoteAddrFunc()
	}
	return
}

// SetDeadline implements the net.Conn interface.
func (m Conn) SetDeadline(t time.Time) (e error) {
	if m.SetDeadlineFunc != nil {
		return m.SetDeadlineFunc(t)
	}
	return
}

// SetReadDeadline implements the net.Conn interface.
func (m Conn) SetReadDeadline(t time.Time) (e error) {
	if m.SetReadDeadlineFunc != nil {
		return m.SetReadDeadlineFunc(t)
	}
	return
}

// SetWriteDeadline implements the net.Conn interface.
func (m Conn) SetWriteDeadline(t time.Time) (e error) {
	if m.SetWriteDeadlineFunc != nil {
		return m.SetWriteDeadlineFunc(t)
	}
	return
}

func NewIOConn() *Conn {
	var bytes bytes2.Buffer
	return &Conn{
		ReadFunc: func(b []byte) (n int, err error) {
			return bytes.Read(b)
		},
		WriteFunc: func(b []byte) (n int, err error) {
			return bytes.Write(b)
		},
	}
}

type MockConnWithBufioxReader struct {
	net.Conn
	BufioxReader bufiox.Reader
}

func (c *MockConnWithBufioxReader) Reader() bufiox.Reader {
	return c.BufioxReader
}
