package main

import (
	"fmt"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/tidbcloud/service-proxy/pkg/audit"
)

var clusterAgentAdditionalSensitiveBodyFields = []string{
	"command",
}

func buildAuditConfig(cfg *Config) *audit.Config {
	if cfg == nil {
		return &audit.Config{}
	}

	return &audit.Config{
		Enabled:             cfg.AuditEnabled,
		FilePath:            cfg.AuditFilePath,
		IncludeGetRequests:  cfg.AuditIncludeGetRequests,
		MaxBodySize:         cfg.AuditMaxBodySize,
		SensitiveBodyFields: clusterAgentAdditionalSensitiveBodyFields,
	}
}

// newAuditManager creates an audit.Manager from the agent config.
// When cfg.AuditEnabled is false, the returned Manager is non-nil but acts as
// a safe no-op: AttachBodyCapture and RecordRequestAutoBody both short-circuit
// internally when the underlying logger is nil.
func newAuditManager(cfg *Config) (*audit.Manager, error) {
	if cfg.AuditEnabled {
		if cfg.AuditFilePath == "" {
			return nil, fmt.Errorf("audit is enabled but --audit-file-path is not set")
		}
		// Note: Further path validation (directory existence, write permissions) is
		// delegated to audit.NewManager, which will return an error if the path is invalid.
	}
	return audit.NewManager(buildAuditConfig(cfg))
}

func HTTPAuditMiddleware(auditManager *audit.Manager, logHealthCheck bool) gin.HandlerFunc {
	return func(c *gin.Context) {
		if auditManager == nil {
			c.Next()
			return
		}

		start := time.Now()
		originalPath := c.Request.URL.Path
		healthCheckPath := httpHealthCheckPath(c)
		rawQuery := c.Request.URL.RawQuery
		c.Request = auditManager.AttachBodyCapture(c.Request)

		c.Next()

		if shouldSkipHTTPHealthCheckLog(logHealthCheck, healthCheckPath, c.Writer.Status()) {
			return
		}

		auditManager.RecordRequestAutoBody(c.Request, audit.RequestRecordOptions{
			Start:        start,
			StatusCode:   c.Writer.Status(),
			OriginalPath: originalPath,
			RawQuery:     rawQuery,
		})
	}
}
