package audit

import (
	"context"
	"database/sql"
	"encoding/json"
	"net/http"
	"strconv"

	"git.dustin.coffee/hobokenchicken/dumpsterChat/internal/middleware"
	"github.com/go-chi/chi/v5"
)

// Handler exposes the audit log read API.
type Handler struct {
	db *sql.DB
}

// NewHandler creates a new audit log handler.
func NewHandler(db *sql.DB) *Handler {
	return &Handler{db: db}
}

// Entry represents a single audit log entry.
type Entry struct {
	ID          string          `json:"id"`
	ServerID    string          `json:"server_id"`
	UserID      *string         `json:"user_id"`
	Username    *string         `json:"username"`
	ActionType  string          `json:"action_type"`
	TargetType  *string         `json:"target_type"`
	TargetID    *string         `json:"target_id"`
	Reason      *string         `json:"reason"`
	Changes     json.RawMessage `json:"changes"`
	CreatedAt   string          `json:"created_at"`
}

// List handles GET /servers/{serverID}/audit-log.
func (h *Handler) List(w http.ResponseWriter, r *http.Request) {
	serverID := chi.URLParam(r, "serverID")
	userID, ok := middleware.UserIDFromContext(r.Context())
	if !ok {
		http.Error(w, `{"error":"unauthorized"}`, http.StatusUnauthorized)
		return
	}

	// ponytail: membership check keeps it simple; MANAGE_SERVER permission is the real gate.
	var isMember bool
	err := h.db.QueryRowContext(r.Context(), `SELECT EXISTS(SELECT 1 FROM members WHERE server_id = $1 AND user_id = $2)`, serverID, userID).Scan(&isMember)
	if err != nil || !isMember {
		http.Error(w, `{"error":"forbidden"}`, http.StatusForbidden)
		return
	}

	limitStr := r.URL.Query().Get("limit")
	limit := 50
	if limitStr != "" {
		if l, err := strconv.Atoi(limitStr); err == nil && l > 0 && l <= 100 {
			limit = l
		}
	}

	actionType := r.URL.Query().Get("action_type")
	before := r.URL.Query().Get("before")

	args := []interface{}{serverID}
	query := `
		SELECT a.id, a.server_id, a.user_id, u.username, a.action_type, a.target_type, a.target_id, a.reason, a.changes, a.created_at::text
		FROM audit_log a
		LEFT JOIN users u ON u.id = a.user_id
		WHERE a.server_id = $1
	`
	if actionType != "" {
		args = append(args, actionType)
		query += ` AND a.action_type = $` + strconv.Itoa(len(args))
	}
	if before != "" {
		args = append(args, before)
		query += ` AND a.created_at < (SELECT created_at FROM audit_log WHERE id = $` + strconv.Itoa(len(args)) + `)`
	}
	query += ` ORDER BY a.created_at DESC LIMIT $` + strconv.Itoa(len(args)+1)
	args = append(args, limit)

	rows, err := h.db.QueryContext(r.Context(), query, args...)
	if err != nil {
		http.Error(w, `{"error":"server error"}`, http.StatusInternalServerError)
		return
	}
	defer rows.Close()

	entries := make([]Entry, 0)
	for rows.Next() {
		var e Entry
		var userIDStr, username, targetType, targetID, reason sql.NullString
		err := rows.Scan(&e.ID, &e.ServerID, &userIDStr, &username, &e.ActionType, &targetType, &targetID, &reason, &e.Changes, &e.CreatedAt)
		if err != nil {
			continue
		}
		if userIDStr.Valid {
			e.UserID = &userIDStr.String
		}
		if username.Valid {
			e.Username = &username.String
		}
		if targetType.Valid {
			e.TargetType = &targetType.String
		}
		if targetID.Valid {
			e.TargetID = &targetID.String
		}
		if reason.Valid {
			e.Reason = &reason.String
		}
		entries = append(entries, e)
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(entries)
}

// Cleanup removes audit log entries older than 90 days.
func (h *Handler) Cleanup(ctx context.Context) error {
	_, err := h.db.ExecContext(ctx, `DELETE FROM audit_log WHERE created_at < NOW() - INTERVAL '90 days'`)
	return err
}
