// Copyright 2023 The uTLS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tls

import (
	
	
	
)

// A UQUICConn represents a connection which uses a QUIC implementation as the underlying
// transport as described in RFC 9001.
//
// Methods of UQUICConn are not safe for concurrent use.
type UQUICConn struct {
	conn *UConn

	sessionTicketSent bool
}

// QUICClient returns a new TLS client side connection using QUICTransport as the
// underlying transport. The config cannot be nil.
//
// The config's MinVersion must be at least TLS 1.3.
func ( *QUICConfig,  ClientHelloID) *UQUICConn {
	return newUQUICConn(UClient(nil, .TLSConfig, ))
}

func ( *UConn) *UQUICConn {
	.quic = &quicState{
		signalc:  make(chan struct{}),
		blockedc: make(chan struct{}),
	}
	.quic.events = .quic.eventArr[:0]
	return &UQUICConn{
		conn: ,
	}
}

// Start starts the client or server handshake protocol.
// It may produce connection events, which may be read with NextEvent.
//
// Start must be called at most once.
func ( *UQUICConn) ( context.Context) error {
	if .conn.quic.started {
		return quicError(errors.New("tls: Start called more than once"))
	}
	.conn.quic.started = true
	if .conn.config.MinVersion < VersionTLS13 {
		return quicError(errors.New("tls: Config MinVersion must be at least TLS 1.13"))
	}
	go .conn.HandshakeContext()
	if ,  := <-.conn.quic.blockedc; ! {
		return .conn.handshakeErr
	}
	return nil
}

func ( *UQUICConn) ( *ClientHelloSpec) error {
	return .conn.ApplyPreset()
}

// NextEvent returns the next event occurring on the connection.
// It returns an event with a Kind of QUICNoEvent when no events are available.
func ( *UQUICConn) () QUICEvent {
	 := .conn.quic
	if  := .nextEvent - 1;  >= 0 && len(.events[].Data) > 0 {
		// Write over some of the previous event's data,
		// to catch callers erroniously retaining it.
		.events[].Data[0] = 0
	}
	if .nextEvent >= len(.events) {
		.events = .events[:0]
		.nextEvent = 0
		return QUICEvent{Kind: QUICNoEvent}
	}
	 := .events[.nextEvent]
	.events[.nextEvent] = QUICEvent{} // zero out references to data
	.nextEvent++
	return 
}

// Close closes the connection and stops any in-progress handshake.
func ( *UQUICConn) () error {
	if .conn.quic.cancel == nil {
		return nil // never started
	}
	.conn.quic.cancel()
	for range .conn.quic.blockedc {
		// Wait for the handshake goroutine to return.
	}
	return .conn.handshakeErr
}

// HandleData handles handshake bytes received from the peer.
// It may produce connection events, which may be read with NextEvent.
func ( *UQUICConn) ( QUICEncryptionLevel,  []byte) error {
	 := .conn
	if .in.level !=  {
		return quicError(.in.setErrorLocked(errors.New("tls: handshake data received at wrong level")))
	}
	.quic.readbuf = 
	<-.quic.signalc
	,  := <-.quic.blockedc
	if  {
		// The handshake goroutine is waiting for more data.
		return nil
	}
	// The handshake goroutine has exited.
	.handshakeMutex.Lock()
	defer .handshakeMutex.Unlock()
	.hand.Write(.quic.readbuf)
	.quic.readbuf = nil
	for .conn.hand.Len() >= 4 && .conn.handshakeErr == nil {
		 := .conn.hand.Bytes()
		 := int([1])<<16 | int([2])<<8 | int([3])
		if  > maxHandshake {
			.conn.handshakeErr = fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", , maxHandshake)
			break
		}
		if len() < 4+ {
			return nil
		}
		if  := .conn.handlePostHandshakeMessage();  != nil {
			.conn.handshakeErr = 
		}
	}
	if .conn.handshakeErr != nil {
		return quicError(.conn.handshakeErr)
	}
	return nil
}

// SendSessionTicket sends a session ticket to the client.
// It produces connection events, which may be read with NextEvent.
// Currently, it can only be called once.
func ( *UQUICConn) ( QUICSessionTicketOptions) error {
	 := .conn
	if !.isHandshakeComplete.Load() {
		return quicError(errors.New("tls: SendSessionTicket called before handshake completed"))
	}
	if .isClient {
		return quicError(errors.New("tls: SendSessionTicket called on the client"))
	}
	if .sessionTicketSent {
		return quicError(errors.New("tls: SendSessionTicket called multiple times"))
	}
	.sessionTicketSent = true
	return quicError(.sendSessionTicket(.EarlyData, .Extra))
}

// ConnectionState returns basic TLS details about the connection.
func ( *UQUICConn) () ConnectionState {
	return .conn.ConnectionState()
}

// SetTransportParameters sets the transport parameters to send to the peer.
//
// Server connections may delay setting the transport parameters until after
// receiving the client's transport parameters. See QUICTransportParametersRequired.
func ( *UQUICConn) ( []byte) {
	if  == nil {
		 = []byte{}
	}
	.conn.quic.transportParams =  // this won't be used for building ClientHello when using a preset

	// // instead, we set the transport parameters hold by the ClientHello
	// for _, ext := range q.conn.Extensions {
	// 	if qtp, ok := ext.(*QUICTransportParametersExtension); ok {
	// 		qtp.TransportParametersExtData = params
	// 	}
	// }

	if .conn.quic.started {
		<-.conn.quic.signalc
		<-.conn.quic.blockedc
	}
}

func ( *UConn) ( QUICEncryptionLevel,  uint16,  []byte) {
	.quic.events = append(.quic.events, QUICEvent{
		Kind:  QUICSetReadSecret,
		Level: ,
		Suite: ,
		Data:  ,
	})
}

func ( *UConn) ( QUICEncryptionLevel,  uint16,  []byte) {
	.quic.events = append(.quic.events, QUICEvent{
		Kind:  QUICSetWriteSecret,
		Level: ,
		Suite: ,
		Data:  ,
	})
}

func ( *UConn) () ([]byte, error) {
	if .quic.transportParams == nil {
		.quic.events = append(.quic.events, QUICEvent{
			Kind: QUICTransportParametersRequired,
		})
	}
	for .quic.transportParams == nil {
		if  := .quicWaitForSignal();  != nil {
			return nil, 
		}
	}
	return .quic.transportParams, nil
}