package admin

import (
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/Wei-Shaw/sub2api/internal/pkg/response"
	"github.com/Wei-Shaw/sub2api/internal/server/middleware"
	"github.com/Wei-Shaw/sub2api/internal/service"

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

// AuditLogHandler 操作审计日志管理接口。
// 审计日志仅管理员可见；不提供单条删除，仅支持带 TOTP 验证的全量清空。
type AuditLogHandler struct {
	auditService *service.AuditLogService
	totpService  *service.TotpService
}

// NewAuditLogHandler 创建审计日志处理器。
func NewAuditLogHandler(auditService *service.AuditLogService, totpService *service.TotpService) *AuditLogHandler {
	return &AuditLogHandler{
		auditService: auditService,
		totpService:  totpService,
	}
}

// List 分页查询审计日志。
// GET /api/v1/admin/audit-logs
func (h *AuditLogHandler) List(c *gin.Context) {
	page, pageSize := response.ParsePagination(c)
	if pageSize > 200 {
		pageSize = 200
	}

	filter := &service.AuditLogFilter{
		Page:       page,
		PageSize:   pageSize,
		ActorEmail: strings.TrimSpace(c.Query("actor_email")),
		AuthMethod: strings.TrimSpace(c.Query("auth_method")),
		Action:     strings.TrimSpace(c.Query("action")),
		Method:     strings.TrimSpace(c.Query("method")),
		ClientIP:   strings.TrimSpace(c.Query("client_ip")),
		Query:      strings.TrimSpace(c.Query("q")),
	}

	if v := strings.TrimSpace(c.Query("actor_user_id")); v != "" {
		id, err := strconv.ParseInt(v, 10, 64)
		if err != nil || id <= 0 {
			response.BadRequest(c, "Invalid actor_user_id")
			return
		}
		filter.ActorUserID = &id
	}
	if v := strings.TrimSpace(c.Query("start_time")); v != "" {
		t, err := time.Parse(time.RFC3339, v)
		if err != nil {
			response.BadRequest(c, "Invalid start_time, expect RFC3339")
			return
		}
		filter.StartTime = &t
	}
	if v := strings.TrimSpace(c.Query("end_time")); v != "" {
		t, err := time.Parse(time.RFC3339, v)
		if err != nil {
			response.BadRequest(c, "Invalid end_time, expect RFC3339")
			return
		}
		filter.EndTime = &t
	}
	if v := strings.TrimSpace(c.Query("success")); v != "" {
		success := v == "true"
		filter.Success = &success
	}

	result, err := h.auditService.List(c.Request.Context(), filter)
	if err != nil {
		response.ErrorFrom(c, err)
		return
	}
	response.Paginated(c, result.Logs, int64(result.Total), result.Page, result.PageSize)
}

// Get 查询单条审计日志详情（含脱敏后的请求体）。
// GET /api/v1/admin/audit-logs/:id
func (h *AuditLogHandler) Get(c *gin.Context) {
	id, err := strconv.ParseInt(strings.TrimSpace(c.Param("id")), 10, 64)
	if err != nil || id <= 0 {
		response.BadRequest(c, "Invalid audit log id")
		return
	}
	item, err := h.auditService.GetByID(c.Request.Context(), id)
	if err != nil {
		response.ErrorFrom(c, err)
		return
	}
	response.Success(c, item)
}

type auditLogClearRequest struct {
	TotpCode string `json:"totp_code" binding:"required"`
}

// Clear 全量清空审计日志。
// POST /api/v1/admin/audit-logs/clear
//
// 安全要求（与需求对齐）：
//  1. 每次清空都必须现场验证 TOTP 码（不复用 step-up sudo 窗口）
//  2. 未启用 TOTP 的管理员不允许清空
//  3. admin API key（机器凭证）不允许清空
//  4. 清空完成后同步写入一条留痕记录（操作者、IP、UA、删除行数）
func (h *AuditLogHandler) Clear(c *gin.Context) {
	if c.GetString("auth_method") == service.AuditAuthMethodAdminAPIKey {
		response.ErrorWithDetails(c, http.StatusForbidden,
			"Admin API key cannot clear audit logs; a two-factor verified admin session is required",
			"STEP_UP_ADMIN_API_KEY_FORBIDDEN", nil)
		return
	}

	subject, ok := middleware.GetAuthSubjectFromContext(c)
	if !ok || subject.UserID <= 0 {
		response.Unauthorized(c, "Unauthorized")
		return
	}

	var req auditLogClearRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.ErrorWithDetails(c, http.StatusBadRequest,
			"TOTP code is required to clear audit logs", "TOTP_CODE_REQUIRED", nil)
		return
	}

	// 校验 TOTP：未启用（ErrTotpNotSetup）、码错误、尝试过多均在此拦截。
	if err := h.totpService.VerifyCode(c.Request.Context(), subject.UserID, strings.TrimSpace(req.TotpCode)); err != nil {
		response.ErrorFrom(c, err)
		return
	}

	uid := subject.UserID
	role, _ := middleware.GetUserRoleFromContext(c)
	trace := &service.AuditLog{
		ActorUserID:      &uid,
		ActorEmail:       c.GetString(middleware.ContextKeyAuthEmail),
		ActorRole:        role,
		AuthMethod:       c.GetString("auth_method"),
		CredentialMasked: middleware.MaskedRequestCredential(c),
		Method:           http.MethodPost,
		Path:             c.FullPath(),
		ClientIP:         middleware.SecurityClientIP(c),
		UserAgent:        c.Request.UserAgent(),
		StatusCode:       http.StatusOK,
	}
	if requestID := c.Writer.Header().Get("X-Request-ID"); requestID != "" {
		trace.RequestID = requestID
	}

	deleted, err := h.auditService.ClearAll(c.Request.Context(), trace)
	if err != nil {
		response.ErrorFrom(c, err)
		return
	}

	// 留痕记录已同步落库，跳过异步审计中间件的重复记录。
	middleware.SkipAudit(c)
	response.Success(c, gin.H{"deleted": deleted})
}
