package middleware

import (
	"crypto/sha256"
	"encoding/hex"
	"log/slog"
	"net/http"
	"strings"
	"time"

	"github.com/gin-gonic/gin"

	"security-center-backend/internal/config"
	"security-center-backend/internal/model"
	"security-center-backend/internal/pkg/response"
	"security-center-backend/internal/repository"
	"security-center-backend/internal/service/jwt"
)

// AgentAuth 验证 X-API-Key, 命中则注入与人类 JWT 同构的 Claims。
func AgentAuth(repo repository.APIKeyRepository, cfg config.AgentConfig) gin.HandlerFunc {
	return func(c *gin.Context) {
		raw := strings.TrimSpace(c.GetHeader("X-API-Key"))
		if raw == "" {
			// 防御分支: 实际装配中 CombinedAuth 已判头, 不会走到这里。
			c.Next()
			return
		}
		if !cfg.Enabled {
			response.Error(c, http.StatusForbidden, "agent access disabled")
			c.Abort()
			return
		}
		hash := sha256Hex(raw)
		rec, err := repo.FindByHash(c.Request.Context(), hash)
		if err != nil || rec == nil {
			response.Error(c, http.StatusUnauthorized, "invalid api key")
			c.Abort()
			return
		}
		if rec.Status == model.APIKeyStatusRevoked {
			response.Error(c, http.StatusUnauthorized, "api key revoked")
			c.Abort()
			return
		}
		if rec.ExpiresAt != nil && rec.ExpiresAt.Before(time.Now()) {
			response.Error(c, http.StatusUnauthorized, "api key expired")
			c.Abort()
			return
		}
		// 主人状态校验 (plan 003 §5.2①): 主人离职/禁用/软删(Owner 缺失)时其 API Key 立即失效。
		// 位置在 revoked/expired 之后、scope 之前: 与 401 认证级判定归为一组, 先于 403 授权级判定。
		if rec.Owner == nil || rec.Owner.Status != model.UserStatusActive {
			ownerStatus := "missing"
			if rec.Owner != nil {
				ownerStatus = string(rec.Owner.Status)
			}
			slog.Warn("agent api key rejected: owner not active",
				"api_key_id", rec.ID, "owner_user_id", rec.OwnerUserID, "owner_status", ownerStatus)
			response.Error(c, http.StatusUnauthorized, "api key owner disabled")
			c.Abort()
			return
		}
		perms := []string(rec.PermissionScope)
		if !scopeAllowedForAgent(perms) {
			slog.Warn("agent api key rejected: scope outside agent allowlist",
				"api_key_id", rec.ID, "agent_name", rec.AgentName, "scopes", perms)
			response.Error(c, http.StatusForbidden, "agent scope not allowed")
			c.Abort()
			return
		}
		// 异步更新 last_used_at, 不阻塞认证热路径。
		touchLastUsedAsync(repo, rec.ID)

		claims := &jwt.Claims{
			UserID:          rec.OwnerUserID,
			Permissions:     perms,
			ActorType:       "agent",
			AgentID:         rec.ID,
			AgentName:       rec.AgentName,
			DelegatedUserID: rec.OwnerUserID,
		}
		c.Set("current_user", claims)
		c.Set("auth_method", "agent")
		c.Set("api_key_id", rec.ID)
		// 把 agent claims 注入请求上下文, 业务层经 AgentClaimsFromContext 读取 (plan 002 §3.2);
		// 人类 JWT 请求不经过本中间件成功分支, 上下文中不会有 claims。
		c.Request = c.Request.WithContext(WithAgentClaims(c.Request.Context(), claims))
		c.Next()
	}
}

// sha256Hex 返回输入的 sha256 hex 摘要, 与 API key 落库哈希口径一致。
func sha256Hex(raw string) string {
	sum := sha256.Sum256([]byte(raw))
	return hex.EncodeToString(sum[:])
}
