package shared

import (
	"hyapp-admin-server/internal/middleware"
	"hyapp-admin-server/internal/model"

	"github.com/gin-gonic/gin"
)

type OperationEvent struct {
	RequestID  string
	UserID     uint
	Username   string
	Action     string
	Resource   string
	ResourceID string
	Method     string
	Path       string
	IP         string
	UserAgent  string
	Status     string
	HTTPStatus int
	RiskLevel  string
	LatencyMS  int64
	Detail     string
}

type OperationLogger interface {
	CreateOperationLog(log model.OperationLog) error
	LogOperation(event OperationEvent) error
}

func OperationLog(c *gin.Context, logger OperationLogger, action string, resource string, status string, detail string) {
	OperationLogWithResourceID(c, logger, action, resource, c.Param("id"), status, detail)
}

// OperationLogWithResourceID is the explicit audit entry point for routes whose target id
// does not use the shared ":id" path parameter name.
func OperationLogWithResourceID(c *gin.Context, logger OperationLogger, action string, resource string, resourceID string, status string, detail string) {
	if logger == nil {
		return
	}
	// MarkAuditLogged keeps middleware from creating a second generic row for this write.
	middleware.MarkAuditLogged(c)
	_ = logger.LogOperation(operationEvent(c, action, resource, resourceID, status, detail))
}

// OperationLogWithResourceIDStrict 是 fail-closed 版本：审计写失败时返回错误、且不抑制
// middleware 的兜底审计行。用于“操作本身在别处不留任何痕迹”的高危动作（如重签用户 token）——
// 这类动作宁可失败，也不能在没有任何审计记录的情况下成功。
func OperationLogWithResourceIDStrict(c *gin.Context, logger OperationLogger, action string, resource string, resourceID string, status string, detail string) error {
	if logger == nil {
		return nil
	}
	if err := logger.LogOperation(operationEvent(c, action, resource, resourceID, status, detail)); err != nil {
		return err
	}
	middleware.MarkAuditLogged(c)
	return nil
}

func operationEvent(c *gin.Context, action string, resource string, resourceID string, status string, detail string) OperationEvent {
	return OperationEvent{
		RequestID:  middleware.CurrentRequestID(c),
		UserID:     middleware.CurrentUserID(c),
		Username:   middleware.CurrentUsername(c),
		Action:     action,
		Resource:   resource,
		ResourceID: resourceID,
		Method:     c.Request.Method,
		Path:       c.Request.URL.Path,
		IP:         c.ClientIP(),
		UserAgent:  c.Request.UserAgent(),
		Status:     status,
		HTTPStatus: c.Writer.Status(),
		Detail:     detail,
	}
}
