package logging

// A CloseReason is the reason why a QUIC connection is closed.
// It falls in one of 4 categories:
// 1. The application closed the connection (with an application-specific error code).
// 2. The transport closed the connection with a transport-error code.
// 3. The connection timed out, either during the handshake, or due to an idle timeout.
// 4. A stateless reset was received.
type CloseReason struct {
	remote           bool
	applicationError *ApplicationError
	transportError   *TransportError

	timeout             *TimeoutReason
	statelessResetToken *StatelessResetToken
}

// NewApplicationCloseReason creates a new CloseReason for an application error.
func NewApplicationCloseReason(errorCode ApplicationError, remote bool) CloseReason {
	return CloseReason{remote: remote, applicationError: &errorCode}
}

// NewTransportCloseReason creates a new CloseReason for a transport error.
func NewTransportCloseReason(errorCode TransportError, remote bool) CloseReason {
	return CloseReason{remote: remote, transportError: &errorCode}
}

// NewTimeoutCloseReason creates a new CloseReason for a connection timeout.
func NewTimeoutCloseReason(r TimeoutReason) CloseReason {
	return CloseReason{timeout: &r}
}

// NewStatelessResetCloseReason creates a new CloseReason for a stateless reset.
func NewStatelessResetCloseReason(token StatelessResetToken) CloseReason {
	return CloseReason{statelessResetToken: &token}
}

// ApplicationError gets the application error.
func (r *CloseReason) ApplicationError() (errorCode ApplicationError, remote bool, ok bool) {
	if r.applicationError == nil {
		return
	}
	return *r.applicationError, r.remote, true
}

// TransportError gets the transport error.
func (r *CloseReason) TransportError() (errorCode TransportError, remote bool, ok bool) {
	if r.transportError == nil {
		return
	}
	return *r.transportError, r.remote, true
}

// Timeout gets the timeout error.
func (r *CloseReason) Timeout() (reason TimeoutReason, ok bool) {
	if r.timeout == nil {
		return
	}
	return *r.timeout, true
}

// StatelessReset gets the stateless reset token.
func (r *CloseReason) StatelessReset() (token StatelessResetToken, ok bool) {
	if r.statelessResetToken == nil {
		return
	}
	return *r.statelessResetToken, true
}
