// Copyright 2026 The Go 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 http2

import (
	"context"
	"crypto/tls"
	"errors"
	"io"
	"log"
	"mime/multipart"
	"net"
	"net/http/internal"
	"net/textproto"
	"net/url"
	"time"
)

// Since net/http imports the http2 package, http2 cannot use any net/http types.
// This file contains definitions which exist to to avoid introducing a dependency cycle.

// Variables defined in net/http and initialized by an init func in that package.
//
// NoBody and LocalAddrContextKey have concrete types in net/http,
// and therefore can't be moved into a common package without introducing
// a dependency cycle.
var (
	NoBody              io.ReadCloser
	LocalAddrContextKey any
)

var (
	ErrAbortHandler    = internal.ErrAbortHandler
	ErrBodyNotAllowed  = internal.ErrBodyNotAllowed
	ErrNotSupported    = errors.ErrUnsupported
	ErrSkipAltProtocol = internal.ErrSkipAltProtocol
)

// A ClientRequest is a Request used by the HTTP/2 client (Transport).
type ClientRequest struct {
	Context       context.Context
	Method        string
	URL           *url.URL
	Header        Header
	Trailer       Header
	Body          io.ReadCloser
	Host          string
	GetBody       func() (io.ReadCloser, error)
	ContentLength int64
	Cancel        <-chan struct{}
	Close         bool
	ResTrailer    *Header

	// Include the per-request stream in the ClientRequest to avoid an allocation.
	stream clientStream
}

// Clone makes a shallow copy of ClientRequest.
//
// Clone is only used in shouldRetryRequest.
// We can drop it if we ever get rid of or rework that function.
func (req *ClientRequest) Clone() *ClientRequest {
	return &ClientRequest{
		Context:       req.Context,
		Method:        req.Method,
		URL:           req.URL,
		Header:        req.Header,
		Trailer:       req.Trailer,
		Body:          req.Body,
		Host:          req.Host,
		GetBody:       req.GetBody,
		ContentLength: req.ContentLength,
		Cancel:        req.Cancel,
		Close:         req.Close,
		ResTrailer:    req.ResTrailer,
	}
}

// A ClientResponse is a Request used by the HTTP/2 client (Transport).
type ClientResponse struct {
	Status        string // e.g. "200"
	StatusCode    int    // e.g. 200
	ContentLength int64
	Uncompressed  bool
	Header        Header
	Trailer       Header
	Body          io.ReadCloser
	TLS           *tls.ConnectionState
}

type Header = textproto.MIMEHeader

// TransportConfig is configuration from an http.Transport.
type TransportConfig interface {
	MaxHeaderListSize() int64
	MaxResponseHeaderBytes() int64
	DisableCompression() bool
	DisableKeepAlives() bool
	ExpectContinueTimeout() time.Duration
	ResponseHeaderTimeout() time.Duration
	IdleConnTimeout() time.Duration
	HTTP2Config() Config
}

// ServerConfig is configuration from an http.Server.
type ServerConfig interface {
	MaxHeaderBytes() int
	MaxHeaderValueCount() int
	ConnState(net.Conn, ConnState)
	DoKeepAlives() bool
	WriteTimeout() time.Duration
	SendPingTimeout() time.Duration
	ErrorLog() *log.Logger
	ReadTimeout() time.Duration
	HTTP2Config() Config
	DisableClientPriority() bool
	IdleTimeout() time.Duration
}

type Handler interface {
	ServeHTTP(*ResponseWriter, *ServerRequest)
}

type ResponseWriter = responseWriter

type PushOptions struct {
	Method string
	Header Header
}

// A ServerRequest is a Request used by the HTTP/2 server.
type ServerRequest struct {
	Context       context.Context
	Proto         string // e.g. "HTTP/1.0"
	ProtoMajor    int    // e.g. 1
	ProtoMinor    int    // e.g. 0
	Method        string
	URL           *url.URL
	Header        Header
	Trailer       Header
	Body          io.ReadCloser
	Host          string
	ContentLength int64
	RemoteAddr    string
	RequestURI    string
	TLS           *tls.ConnectionState
	MultipartForm *multipart.Form
}

// ConnState is identical to net/http.ConnState.
type ConnState int

const (
	ConnStateNew ConnState = iota
	ConnStateActive
	ConnStateIdle
	ConnStateHijacked
	ConnStateClosed
)
