package readstate

import (
	"database/sql"
	"encoding/json"
	"log/slog"
	"net/http"

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

type Handler struct {
	db     *sql.DB
	logger *slog.Logger
}

func NewHandler(db *sql.DB, logger *slog.Logger) *Handler {
	return &Handler{db: db, logger: logger}
}

func (h *Handler) RegisterRoutes(r chi.Router) {
	r.Put("/{channelID}/read", h.MarkRead)
	r.Get("/users/me/read-states", h.GetAll)
}

type markReadRequest struct {
	LastReadMessageID string `json:"last_read_message_id"`
}

func (h *Handler) MarkRead(w http.ResponseWriter, r *http.Request) {
	userID, _ := middleware.UserIDFromContext(r.Context())
	channelID := chi.URLParam(r, "channelID")

	var req markReadRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, `{"error":"invalid JSON"}`, http.StatusBadRequest)
		return
	}
	if req.LastReadMessageID == "" {
		http.Error(w, `{"error":"last_read_message_id is required"}`, http.StatusBadRequest)
		return
	}

	_, err := h.db.Exec(`
		INSERT INTO read_states (user_id, channel_id, last_read_message_id, updated_at)
		VALUES ($1, $2, $3, NOW())
		ON CONFLICT (user_id, channel_id) DO UPDATE SET
			last_read_message_id = $3,
			updated_at = NOW()
	`, userID, channelID, req.LastReadMessageID)
	if err != nil {
		h.logger.Error("failed to mark read", "error", err)
		http.Error(w, `{"error":"internal error"}`, http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
}

// ChannelReadState is returned per channel
type ChannelReadState struct {
	ChannelID          string `json:"channel_id"`
	LastReadMessageID  string `json:"last_read_message_id"`
}

func (h *Handler) GetAll(w http.ResponseWriter, r *http.Request) {
	userID, _ := middleware.UserIDFromContext(r.Context())

	rows, err := h.db.Query(`
		SELECT rs.channel_id, rs.last_read_message_id
		FROM read_states rs
		WHERE rs.user_id = $1
	`, userID)
	if err != nil {
		h.logger.Error("failed to query read states", "error", err)
		http.Error(w, `{"error":"internal error"}`, http.StatusInternalServerError)
		return
	}
	defer rows.Close()

	states := make(map[string]string)
	for rows.Next() {
		var channelID, lastReadMessageID string
		if err := rows.Scan(&channelID, &lastReadMessageID); err != nil {
			continue
		}
		states[channelID] = lastReadMessageID
	}

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