package handlers

import (
	"context"
	"encoding/json"
	"log"
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"github.com/jackc/pgx/v5/pgxpool"
	"gitlab.com/patrickbritton3/sojorn/go-backend/internal/services"
)

type BoardHandler struct {
	pool              *pgxpool.Pool
	contentFilter     *services.ContentFilter
	moderationService *services.ModerationService
}

func NewBoardHandler(pool *pgxpool.Pool, opts ...interface{}) *BoardHandler {
	h := &BoardHandler{pool: pool}
	for _, opt := range opts {
		switch v := opt.(type) {
		case *services.ContentFilter:
			h.contentFilter = v
		case *services.ModerationService:
			h.moderationService = v
		}
	}
	return h
}

// ── List nearby board entries ─────────────────────────────────────────────

func (h *BoardHandler) ListNearby(c *gin.Context) {
	userIDStr, _ := c.Get("user_id")
	userID, _ := uuid.Parse(userIDStr.(string))

	latStr := c.Query("lat")
	longStr := c.Query("long")
	radiusStr := c.DefaultQuery("radius", "5000")
	topic := c.Query("topic")
	sort := c.DefaultQuery("sort", "new")

	lat, err := strconv.ParseFloat(latStr, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "lat required"})
		return
	}
	long, err := strconv.ParseFloat(longStr, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "long required"})
		return
	}
	radius, _ := strconv.Atoi(radiusStr)
	if radius <= 0 || radius > 50000 {
		radius = 5000
	}

	query := `
		SELECT e.id, e.body, COALESCE(e.image_url, ''), e.topic,
		       e.lat, e.long, e.upvotes, e.reply_count, e.is_pinned, e.created_at,
		       pr.handle, pr.display_name, COALESCE(pr.avatar_url, ''),
		       EXISTS(SELECT 1 FROM board_votes bv WHERE bv.user_id = $4 AND bv.entry_id = e.id) AS has_voted
		FROM board_entries e
		JOIN profiles pr ON e.author_id = pr.id
		WHERE e.is_active = TRUE
		  AND ST_DWithin(e.location, ST_SetSRID(ST_Point($2, $1), 4326)::geography, $3)
	`
	args := []any{lat, long, radius, userID}
	argIdx := 5

	if topic != "" {
		query += ` AND e.topic = $` + strconv.Itoa(argIdx)
		args = append(args, topic)
		argIdx++
	}

	orderClause := "e.is_pinned DESC, e.created_at DESC"
	switch sort {
	case "top":
		orderClause = "e.is_pinned DESC, e.upvotes DESC, e.reply_count DESC, e.created_at DESC"
	case "hot":
		orderClause = "e.is_pinned DESC, (e.upvotes * 2 + e.reply_count) DESC, e.created_at DESC"
	}

	query += ` ORDER BY ` + orderClause + ` LIMIT 100`

	rows, err := h.pool.Query(c.Request.Context(), query, args...)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch board entries"})
		return
	}
	defer rows.Close()

	var entries []gin.H
	for rows.Next() {
		var id uuid.UUID
		var body, imageURL, tp, handle, displayName, avatarURL string
		var eLat, eLong float64
		var upvotes, replyCount int
		var isPinned, hasVoted bool
		var createdAt time.Time
		if err := rows.Scan(&id, &body, &imageURL, &tp,
			&eLat, &eLong, &upvotes, &replyCount, &isPinned, &createdAt,
			&handle, &displayName, &avatarURL, &hasVoted); err != nil {
			continue
		}
		entries = append(entries, gin.H{
			"id": id, "body": body, "image_url": imageURL, "topic": tp,
			"lat": eLat, "long": eLong, "upvotes": upvotes, "reply_count": replyCount,
			"is_pinned": isPinned, "created_at": createdAt,
			"author_handle": handle, "author_display_name": displayName, "author_avatar_url": avatarURL,
			"has_voted": hasVoted,
		})
	}
	if entries == nil {
		entries = []gin.H{}
	}

	// Check if the current user is a neighborhood admin for any nearby group
	isAdmin := h.isNeighborhoodAdmin(c, userID, lat, long)

	c.JSON(http.StatusOK, gin.H{"entries": entries, "is_neighborhood_admin": isAdmin})
}

// ── Create board entry ────────────────────────────────────────────────────

func (h *BoardHandler) CreateEntry(c *gin.Context) {
	userIDStr, _ := c.Get("user_id")
	userID, err := uuid.Parse(userIDStr.(string))
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
		return
	}

	var req struct {
		Body     string  `json:"body" binding:"required,max=1000"`
		ImageURL *string `json:"image_url"`
		Topic    string  `json:"topic"`
		Lat      float64 `json:"lat" binding:"required"`
		Long     float64 `json:"long" binding:"required"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if req.Topic == "" {
		req.Topic = "community"
	}

	// Layer 0: Hard blocklist check (instant rejection)
	if h.contentFilter != nil {
		result := h.contentFilter.CheckContent(req.Body)
		if result.Blocked {
			go h.contentFilter.RecordStrike(c.Request.Context(), userID, result.Category, req.Body)
			c.JSON(http.StatusForbidden, gin.H{
				"error":    "Content violates community guidelines",
				"category": result.Category,
			})
			return
		}
	}

	var id uuid.UUID
	var createdAt time.Time
	err = h.pool.QueryRow(c.Request.Context(), `
		INSERT INTO board_entries (author_id, body, image_url, topic, lat, long)
		VALUES ($1, $2, $3, $4, $5, $6)
		RETURNING id, created_at
	`, userID, req.Body, req.ImageURL, req.Topic, req.Lat, req.Long).Scan(&id, &createdAt)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create entry"})
		return
	}

	// Layer 1: AI moderation (async — doesn't block the response)
	go h.aiModerateEntry(id, req.Body, userID)

	// Fetch author info for response
	var handle, displayName, avatarURL string
	_ = h.pool.QueryRow(c.Request.Context(),
		`SELECT handle, display_name, COALESCE(avatar_url, '') FROM profiles WHERE id = $1`, userID,
	).Scan(&handle, &displayName, &avatarURL)

	c.JSON(http.StatusCreated, gin.H{"entry": gin.H{
		"id": id, "body": req.Body, "image_url": req.ImageURL, "topic": req.Topic,
		"lat": req.Lat, "long": req.Long, "upvotes": 0, "reply_count": 0,
		"is_pinned": false, "created_at": createdAt,
		"author_handle": handle, "author_display_name": displayName, "author_avatar_url": avatarURL,
		"has_voted": false,
	}})
}

// ── Get single entry with replies ─────────────────────────────────────────

func (h *BoardHandler) GetEntry(c *gin.Context) {
	userIDStr, _ := c.Get("user_id")
	userID, _ := uuid.Parse(userIDStr.(string))
	entryID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid entry id"})
		return
	}

	// Fetch entry
	var body, imageURL, topic, handle, displayName, avatarURL string
	var eLat, eLong float64
	var upvotes, replyCount int
	var isPinned, hasVoted bool
	var createdAt time.Time
	err = h.pool.QueryRow(c.Request.Context(), `
		SELECT e.body, COALESCE(e.image_url, ''), e.topic,
		       e.lat, e.long, e.upvotes, e.reply_count, e.is_pinned, e.created_at,
		       pr.handle, pr.display_name, COALESCE(pr.avatar_url, ''),
		       EXISTS(SELECT 1 FROM board_votes bv WHERE bv.user_id = $2 AND bv.entry_id = e.id) AS has_voted
		FROM board_entries e
		JOIN profiles pr ON e.author_id = pr.id
		WHERE e.id = $1 AND e.is_active = TRUE
	`, entryID, userID).Scan(&body, &imageURL, &topic,
		&eLat, &eLong, &upvotes, &replyCount, &isPinned, &createdAt,
		&handle, &displayName, &avatarURL, &hasVoted)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "entry not found"})
		return
	}

	// Fetch replies
	replyRows, err := h.pool.Query(c.Request.Context(), `
		SELECT r.id, r.body, r.upvotes, r.created_at,
		       pr.handle, pr.display_name, COALESCE(pr.avatar_url, ''),
		       EXISTS(SELECT 1 FROM board_votes bv WHERE bv.user_id = $2 AND bv.reply_id = r.id) AS has_voted
		FROM board_replies r
		JOIN profiles pr ON r.author_id = pr.id
		WHERE r.entry_id = $1 AND r.is_active = TRUE
		ORDER BY r.created_at ASC
	`, entryID, userID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch replies"})
		return
	}
	defer replyRows.Close()

	var replies []gin.H
	for replyRows.Next() {
		var rID uuid.UUID
		var rBody, rHandle, rDisplayName, rAvatarURL string
		var rUpvotes int
		var rCreatedAt time.Time
		var rHasVoted bool
		if err := replyRows.Scan(&rID, &rBody, &rUpvotes, &rCreatedAt,
			&rHandle, &rDisplayName, &rAvatarURL, &rHasVoted); err != nil {
			continue
		}
		replies = append(replies, gin.H{
			"id": rID, "body": rBody, "upvotes": rUpvotes, "created_at": rCreatedAt,
			"author_handle": rHandle, "author_display_name": rDisplayName, "author_avatar_url": rAvatarURL,
			"has_voted": rHasVoted,
		})
	}
	if replies == nil {
		replies = []gin.H{}
	}

	// Check admin status for this entry
	isAdmin := h.isNeighborhoodAdmin(c, userID, eLat, eLong)

	c.JSON(http.StatusOK, gin.H{
		"entry": gin.H{
			"id": entryID, "body": body, "image_url": imageURL, "topic": topic,
			"lat": eLat, "long": eLong, "upvotes": upvotes, "reply_count": replyCount,
			"is_pinned": isPinned, "created_at": createdAt,
			"author_handle": handle, "author_display_name": displayName, "author_avatar_url": avatarURL,
			"has_voted": hasVoted,
		},
		"replies":               replies,
		"is_neighborhood_admin": isAdmin,
	})
}

// ── Reply to entry ────────────────────────────────────────────────────────

func (h *BoardHandler) CreateReply(c *gin.Context) {
	userIDStr, _ := c.Get("user_id")
	userID, err := uuid.Parse(userIDStr.(string))
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
		return
	}
	entryID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid entry id"})
		return
	}

	var req struct {
		Body string `json:"body" binding:"required,max=500"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// Layer 0: Hard blocklist check
	if h.contentFilter != nil {
		result := h.contentFilter.CheckContent(req.Body)
		if result.Blocked {
			go h.contentFilter.RecordStrike(c.Request.Context(), userID, result.Category, req.Body)
			c.JSON(http.StatusForbidden, gin.H{
				"error":    "Content violates community guidelines",
				"category": result.Category,
			})
			return
		}
	}

	var replyID uuid.UUID
	var createdAt time.Time
	err = h.pool.QueryRow(c.Request.Context(), `
		INSERT INTO board_replies (entry_id, author_id, body)
		VALUES ($1, $2, $3)
		RETURNING id, created_at
	`, entryID, userID, req.Body).Scan(&replyID, &createdAt)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create reply"})
		return
	}

	// Bump reply count
	_, _ = h.pool.Exec(c.Request.Context(),
		`UPDATE board_entries SET reply_count = reply_count + 1, updated_at = NOW() WHERE id = $1`, entryID)

	// Layer 1: AI moderation (async)
	go h.aiModerateReply(replyID, req.Body, userID)

	var handle, displayName, avatarURL string
	_ = h.pool.QueryRow(c.Request.Context(),
		`SELECT handle, display_name, COALESCE(avatar_url, '') FROM profiles WHERE id = $1`, userID,
	).Scan(&handle, &displayName, &avatarURL)

	c.JSON(http.StatusCreated, gin.H{"reply": gin.H{
		"id": replyID, "body": req.Body, "upvotes": 0, "created_at": createdAt,
		"author_handle": handle, "author_display_name": displayName, "author_avatar_url": avatarURL,
		"has_voted": false,
	}})
}

// ── Upvote entry or reply (toggle) ────────────────────────────────────────

func (h *BoardHandler) ToggleVote(c *gin.Context) {
	userIDStr, _ := c.Get("user_id")
	userID, err := uuid.Parse(userIDStr.(string))
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
		return
	}

	var req struct {
		EntryID *string `json:"entry_id"`
		ReplyID *string `json:"reply_id"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	ctx := c.Request.Context()

	if req.EntryID != nil && *req.EntryID != "" {
		entryID, err := uuid.Parse(*req.EntryID)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "invalid entry_id"})
			return
		}
		// Try delete (un-vote); if nothing deleted, insert (vote)
		tag, err := h.pool.Exec(ctx,
			`DELETE FROM board_votes WHERE user_id = $1 AND entry_id = $2`, userID, entryID)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "vote failed"})
			return
		}
		if tag.RowsAffected() > 0 {
			_, _ = h.pool.Exec(ctx,
				`UPDATE board_entries SET upvotes = GREATEST(upvotes - 1, 0) WHERE id = $1`, entryID)
			c.JSON(http.StatusOK, gin.H{"voted": false})
			return
		}
		_, err = h.pool.Exec(ctx,
			`INSERT INTO board_votes (user_id, entry_id) VALUES ($1, $2)`, userID, entryID)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "vote failed"})
			return
		}
		_, _ = h.pool.Exec(ctx,
			`UPDATE board_entries SET upvotes = upvotes + 1 WHERE id = $1`, entryID)
		c.JSON(http.StatusOK, gin.H{"voted": true})
		return
	}

	if req.ReplyID != nil && *req.ReplyID != "" {
		replyID, err := uuid.Parse(*req.ReplyID)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "invalid reply_id"})
			return
		}
		tag, err := h.pool.Exec(ctx,
			`DELETE FROM board_votes WHERE user_id = $1 AND reply_id = $2`, userID, replyID)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "vote failed"})
			return
		}
		if tag.RowsAffected() > 0 {
			_, _ = h.pool.Exec(ctx,
				`UPDATE board_replies SET upvotes = GREATEST(upvotes - 1, 0) WHERE id = $1`, replyID)
			c.JSON(http.StatusOK, gin.H{"voted": false})
			return
		}
		_, err = h.pool.Exec(ctx,
			`INSERT INTO board_votes (user_id, reply_id) VALUES ($1, $2)`, userID, replyID)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "vote failed"})
			return
		}
		_, _ = h.pool.Exec(ctx,
			`UPDATE board_replies SET upvotes = upvotes + 1 WHERE id = $1`, replyID)
		c.JSON(http.StatusOK, gin.H{"voted": true})
		return
	}

	c.JSON(http.StatusBadRequest, gin.H{"error": "entry_id or reply_id required"})
}

// ── Admin: Remove board entry ─────────────────────────────────────────────
// Neighborhood admins can remove entries in their neighborhood.
// POST /board/:id/remove

func (h *BoardHandler) RemoveEntry(c *gin.Context) {
	userIDStr, _ := c.Get("user_id")
	userID, err := uuid.Parse(userIDStr.(string))
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
		return
	}
	entryID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid entry id"})
		return
	}

	var req struct {
		Reason string `json:"reason" binding:"required,min=5,max=500"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	ctx := c.Request.Context()

	// Check if the user is a neighborhood admin for the entry's location
	var entryLat, entryLong float64
	err = h.pool.QueryRow(ctx,
		`SELECT lat, long FROM board_entries WHERE id = $1 AND is_active = TRUE`, entryID,
	).Scan(&entryLat, &entryLong)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "entry not found"})
		return
	}

	// Verify caller is neighborhood admin or app admin
	if !h.isNeighborhoodAdmin(c, userID, entryLat, entryLong) {
		c.JSON(http.StatusForbidden, gin.H{"error": "only neighborhood admins can remove content"})
		return
	}

	// Soft-remove the entry
	_, err = h.pool.Exec(ctx, `
		UPDATE board_entries
		SET is_active = FALSE, removed_by = $1, removed_reason = $2, removed_at = NOW(), updated_at = NOW()
		WHERE id = $3
	`, userID, req.Reason, entryID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to remove entry"})
		return
	}

	// Audit trail
	_, _ = h.pool.Exec(ctx, `
		INSERT INTO board_moderation_actions (entry_id, moderator_id, action, reason)
		VALUES ($1, $2, 'remove', $3)
	`, entryID, userID, req.Reason)

	c.JSON(http.StatusOK, gin.H{"message": "entry removed", "entry_id": entryID})
}

// ── Flag board content ────────────────────────────────────────────────────
// Any user can flag board content for review.
// POST /board/:id/flag

func (h *BoardHandler) FlagEntry(c *gin.Context) {
	userIDStr, _ := c.Get("user_id")
	userID, err := uuid.Parse(userIDStr.(string))
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
		return
	}
	entryID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid entry id"})
		return
	}

	var req struct {
		Reason  string  `json:"reason" binding:"required,min=3,max=500"`
		ReplyID *string `json:"reply_id"` // optional: flag a specific reply
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	ctx := c.Request.Context()

	if req.ReplyID != nil && *req.ReplyID != "" {
		replyUUID, err := uuid.Parse(*req.ReplyID)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "invalid reply_id"})
			return
		}
		_, _ = h.pool.Exec(ctx, `
			INSERT INTO board_moderation_actions (reply_id, moderator_id, action, reason)
			VALUES ($1, $2, 'flag', $3)
		`, replyUUID, userID, req.Reason)
	} else {
		_, _ = h.pool.Exec(ctx, `
			INSERT INTO board_moderation_actions (entry_id, moderator_id, action, reason)
			VALUES ($1, $2, 'flag', $3)
		`, entryID, userID, req.Reason)
	}

	c.JSON(http.StatusOK, gin.H{"message": "content flagged for review"})
}

// ── Helpers ───────────────────────────────────────────────────────────────

// isNeighborhoodAdmin checks if a user is an admin/owner of any neighborhood
// group that covers the given coordinates.
func (h *BoardHandler) isNeighborhoodAdmin(c *gin.Context, userID uuid.UUID, lat, long float64) bool {
	var exists bool
	_ = h.pool.QueryRow(c.Request.Context(), `
		SELECT EXISTS(
			SELECT 1
			FROM neighborhood_seeds ns
			JOIN group_members gm ON gm.group_id = ns.group_id
			WHERE gm.user_id = $1
			  AND gm.role IN ('owner', 'admin')
			  AND ST_DWithin(
					ST_SetSRID(ST_Point($3, $2), 4326)::geography,
					ST_SetSRID(ST_Point(ns.lng, ns.lat), 4326)::geography,
					ns.radius_meters
			  )
		)
	`, userID, lat, long).Scan(&exists)
	return exists
}

// aiModerateEntry runs AI moderation on a board entry asynchronously.
// If flagged, it sets ai_flagged = true and hides the entry.
func (h *BoardHandler) aiModerateEntry(entryID uuid.UUID, body string, authorID uuid.UUID) {
	if h.moderationService == nil {
		return
	}
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	score, reason, err := h.moderationService.AnalyzeContent(ctx, body, nil)
	if err != nil {
		log.Printf("[BoardAI] moderation error for entry %s: %v", entryID, err)
		return
	}

	// Always log AI decision for audit
	decision := "clean"
	if reason != "" {
		decision = "flag"
	}
	rawScore, _ := json.Marshal(score)

	h.moderationService.LogAIDecision(ctx, "board_entry", entryID, authorID, body, score, rawScore, decision, reason, "", nil)

	if reason == "" {
		return // clean
	}

	log.Printf("[BoardAI] entry %s flagged: %s", entryID, reason)

	_, _ = h.pool.Exec(ctx, `
		UPDATE board_entries
		SET ai_flagged = TRUE, ai_flag_reason = $1, is_active = FALSE,
		    removed_reason = 'AI auto-moderation: ' || $1, removed_at = NOW(), updated_at = NOW()
		WHERE id = $2
	`, reason, entryID)

	// Log audit trail
	_, _ = h.pool.Exec(ctx, `
		INSERT INTO board_moderation_actions (entry_id, moderator_id, action, reason, ai_engine, ai_reason)
		VALUES ($1, $2, 'remove', $3, 'auto', $3)
	`, entryID, authorID, "AI flagged: "+reason)
}

// aiModerateReply runs AI moderation on a board reply asynchronously.
func (h *BoardHandler) aiModerateReply(replyID uuid.UUID, body string, authorID uuid.UUID) {
	if h.moderationService == nil {
		return
	}
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	score, reason, err := h.moderationService.AnalyzeContent(ctx, body, nil)
	if err != nil {
		log.Printf("[BoardAI] moderation error for reply %s: %v", replyID, err)
		return
	}

	// Always log AI decision for audit
	decision := "clean"
	if reason != "" {
		decision = "flag"
	}
	rawScore, _ := json.Marshal(score)

	h.moderationService.LogAIDecision(ctx, "board_reply", replyID, authorID, body, score, rawScore, decision, reason, "", nil)

	if reason == "" {
		return // clean
	}

	log.Printf("[BoardAI] reply %s flagged: %s", replyID, reason)

	_, _ = h.pool.Exec(ctx, `
		UPDATE board_replies
		SET ai_flagged = TRUE, ai_flag_reason = $1, is_active = FALSE,
		    removed_reason = 'AI auto-moderation: ' || $1, removed_at = NOW()
		WHERE id = $2
	`, reason, replyID)

	// Log audit trail
	_, _ = h.pool.Exec(ctx, `
		INSERT INTO board_moderation_actions (reply_id, moderator_id, action, reason, ai_engine, ai_reason)
		VALUES ($1, $2, 'remove', $3, 'auto', $3)
	`, replyID, authorID, "AI flagged: "+reason)
}
