package connection

import (
	"context"
	"io"
)

type TransportLayer interface {
	// OnNewSession - callback for creating transport layer session and
	// link them with connection layer session
	OnNewSession(Session) (SessionEvents, error)
}

type SessionEvents interface {
	// OnStreamAccept - callback for accepting new stream
	OnStreamAccept(*FrameHeader, FrameReadStream)

	// OnClose - callback that will be called when QUIC connection is closed
	OnClose(error)
}

// SyncRequestReceiver - interface for accepting request in sync mode.
// This interface MUST be implemented by the user for transport layer session
// to call the ListenSession method in connection layer.
type SyncRequestReceiver interface {
	// OnSyncRequest - callback for receiving request in sync mode. Frame body will be read by connection layer.
	// Callback must return response frame header and body
	OnSyncRequest(header *FrameHeader, body []byte) (*FrameHeader, []byte)

	// OnError - callback that will be called if error was occured on connection level for generating frame header with error
	OnError(error) *FrameHeader
}

/******************************************Transport/Connection layers boundary***********************************************/

const (
	MaxHeaderLength = 10 * 1024
	ProtoName       = "quic-wt-proto"
)

type ConnectionLayer interface {
	OpenSession(addr string) (Session, error)

	ListenSession(context context.Context, addr string) error
}

type Session interface {
	OpenStream(context.Context, *FrameHeader) (FrameWriteStream, error)
	GetContext() context.Context

	// SendSyncRequest - method for sending request in sync mode.
	// Sync mode - the mode in which the response comes from the same stream that was used to send the request
	// Arguments: request frame header and body
	// Return: response frame header and body
	SendSyncRequest(context.Context, *FrameHeader, []byte) (*FrameHeader, []byte, error)

	Close()
}

// FrameReadStream - interface for reading transport frames from QUIC stream
type FrameReadStream interface {
	io.Reader
	CancelRead(errCode uint64)
}

// FrameWriteStream - interface for writing transport frames in QUIC stream
type FrameWriteStream interface {
	io.WriteCloser
}

// FrameStream - interface for bidirectional transport frames sending over QUIC stream
type FrameStream interface {
	FrameReadStream
	FrameWriteStream
}

// FrameHeader - struct for description tranposrt frame header
type FrameHeader struct {
	Type       FrameType
	Header     []byte
	BodyLength uint64
}

// FrameType - type for determining tranposrt frame type
type FrameType uint64

// Available transport frame types
const (
	SystemFrameType = iota
	RequestFrameType
	ResponseFrameType
	EventFrameType
)
