package webtransport

import (
	"errors"
	"fmt"

	"github.com/quic-go/quic-go"
)

// StreamErrorCode is an error code used for stream termination.
type StreamErrorCode uint32

// SessionErrorCode is an error code for session termination.
type SessionErrorCode uint32

const (
	firstErrorCode = 0x52e4a40fa8db
	lastErrorCode  = 0x52e5ac983162
)

func webtransportCodeToHTTPCode(n StreamErrorCode) quic.StreamErrorCode {
	return quic.StreamErrorCode(firstErrorCode) + quic.StreamErrorCode(n) + quic.StreamErrorCode(n/0x1e)
}

func httpCodeToWebtransportCode(h quic.StreamErrorCode) (StreamErrorCode, error) {
	if h < firstErrorCode || h > lastErrorCode {
		return 0, errors.New("error code outside of expected range")
	}
	if (h-0x21)%0x1f == 0 {
		return 0, errors.New("invalid error code")
	}
	shifted := h - firstErrorCode
	return StreamErrorCode(shifted - shifted/0x1f), nil
}

const (
	// WTBufferedStreamRejectedErrorCode is the error code of the
	// WT_BUFFERED_STREAM_REJECTED error.
	WTBufferedStreamRejectedErrorCode quic.StreamErrorCode = 0x3994bd84

	// WTSessionGoneErrorCode is the error code of the WT_SESSION_GONE error.
	WTSessionGoneErrorCode quic.StreamErrorCode = 0x170d7b68
)

// StreamError is the error that is returned from stream operations (Read, Write) when the stream is canceled.
type StreamError struct {
	ErrorCode StreamErrorCode
	Remote    bool
}

var _ error = &StreamError{}

func (e *StreamError) Error() string {
	return fmt.Sprintf("stream canceled with error code %d", e.ErrorCode)
}

func (e *StreamError) Is(target error) bool {
	t, ok := target.(*StreamError)
	return ok && t.Remote == e.Remote && t.ErrorCode == e.ErrorCode
}

// SessionError is a WebTransport connection error.
type SessionError struct {
	Remote    bool
	ErrorCode SessionErrorCode
	Message   string
}

var _ error = &SessionError{}

func (e *SessionError) Error() string { return e.Message }

func (e *SessionError) Is(target error) bool {
	t, ok := target.(*SessionError)
	return ok && e.ErrorCode == t.ErrorCode && e.Remote == t.Remote
}
