// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package api

import (
	"net/http"
	"strings"
)

const (
	contentTypeHeader = "Content-Type"
	plainContentType  = "text/plain; charset=utf-8"
	octetStream       = "application/octet-stream"
	jsonContentType   = "application/json; charset=utf-8" // Default content type
)

// ContentTypeRule defines a rule for determining the content type of an HTTP request.
// This rule is based on the combination of the HTTP path, method, and the desired content type.
type ContentTypeRule struct {
	path        string
	httpMethod  string
	contentType string
}

var ContentTypeRules = []ContentTypeRule{
	{
		path:        "/v1/snapshot",
		httpMethod:  http.MethodPut,
		contentType: octetStream,
	},
	{
		path:        "/v1/kv",
		httpMethod:  http.MethodPut,
		contentType: octetStream,
	},
	{
		path:        "/v1/event/fire",
		httpMethod:  http.MethodPut,
		contentType: octetStream,
	},
}

// GetContentType returns the content type for a request
// This function isused as routing logic or middleware to determine and enforce
// the appropriate content type for HTTP requests.
func GetContentType(req *http.Request) string {
	reqContentType := req.Header.Get(contentTypeHeader)

	if isIndexPage(req) {
		return plainContentType
	}

	// For GET, DELETE, or internal API paths, ensure a valid Content-Type is returned.
	if req.Method == http.MethodGet || req.Method == http.MethodDelete || strings.HasPrefix(req.URL.Path, "/v1/internal") {
		if reqContentType == "" {
			// Default to JSON Content-Type if no Content-Type is provided.
			return jsonContentType
		}
		// Return the provided Content-Type if it exists.
		return reqContentType
	}

	for _, rule := range ContentTypeRules {
		if matchesRule(req, rule) {
			return rule.contentType
		}
	}
	return jsonContentType
}

// matchesRule checks if a request matches a content type rule
func matchesRule(req *http.Request, rule ContentTypeRule) bool {
	return strings.HasPrefix(req.URL.Path, rule.path) &&
		(rule.httpMethod == "" || req.Method == rule.httpMethod)
}

// isIndexPage checks if the request is for the index page
func isIndexPage(req *http.Request) bool {
	return req.URL.Path == "/" || req.URL.Path == "/ui"
}
