package proxy

import (
	"net/http"
	"net/url"
	"time"

	packagev1 "buf.build/gen/go/safedep/api/protocolbuffers/go/safedep/messages/package/v1"
)

// ResponseAction determines how the proxy should handle a request
type ResponseAction int

const (
	// ActionAllow forwards the request unchanged
	ActionAllow ResponseAction = iota

	// ActionBlock blocks the request with an error response
	ActionBlock

	// ActionModifyRequest modifies the request before forwarding
	ActionModifyRequest

	// ActionModifyResponse modifies the response after receiving
	ActionModifyResponse
)

// RequestContext provides request information to interceptors
// This is passed to ShouldIntercept and HandleRequest methods
type RequestContext struct {
	URL     *url.URL
	Method  string
	Headers http.Header

	// Body is not currently used by the interceptors, but it is here for future use
	Body []byte

	Hostname  string
	RequestID string
	StartTime time.Time

	// Interceptor can store custom data
	Data map[string]interface{}
}

// BlockReason identifies why an interceptor blocked a request
type BlockReason int

const (
	BlockReasonNone BlockReason = iota
	BlockReasonMalware
	BlockReasonUserDeclined
	BlockReasonConfirmationFailed
	BlockReasonDependencyCooldown
)

// BlockContext carries the structured facts of a block decision so a
// presentation layer can render the user-facing message. Interceptors
// populate it instead of composing message text themselves.
type BlockContext struct {
	Ecosystem      packagev1.Ecosystem
	PackageName    string
	PackageVersion string

	// For BlockReasonMalware and BlockReasonUserDeclined
	MalwareSummary      string
	MalwareReferenceURL string

	// For BlockReasonDependencyCooldown
	CooldownDays     int
	CooldownDaysAgo  int
	CooldownDaysLeft int
}

// InterceptorResponse defines how the proxy should handle the request
type InterceptorResponse struct {
	// Action to take
	Action ResponseAction

	// For Action = Block: why and what was blocked. The proxy renders the
	// response body from these via ProxyConfig.BlockMessageRenderer.
	BlockReason  BlockReason
	BlockContext *BlockContext

	// BlockMessage overrides the rendered message when non-empty
	BlockMessage string
	BlockCode    int

	// For Action = ModifyRequest: modified headers/body
	ModifiedHeaders http.Header

	// ModifiedBody is not currently used by the interceptors, but it is here for future use
	ModifiedBody []byte

	// For Action = ModifyResponse: response modification function
	ResponseModifier ResponseModifierFunc
}

// ResponseModifierFunc modifies HTTP response
// It receives the status code, headers, and body, and returns modified versions
type ResponseModifierFunc func(statusCode int, headers http.Header, body []byte) (int, http.Header, []byte, error)

// Interceptor processes HTTP/HTTPS requests and can modify or block them
type Interceptor interface {
	// Name returns the interceptor name for logging
	Name() string

	// ShouldIntercept determines if this interceptor handles the given request
	ShouldIntercept(ctx *RequestContext) bool

	// HandleRequest processes the request and returns response action
	// Called for each request matching ShouldIntercept
	HandleRequest(ctx *RequestContext) (*InterceptorResponse, error)
}

// MITMDecider is optional; implement to control whether CONNECT requests are MITM’d.
type MITMDecider interface {
	ShouldMITM(ctx *RequestContext) bool
}
