package server

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

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

type MemberHandler struct {
	db      *sql.DB
	checker *permissions.Checker
}

func NewMemberHandler(db *sql.DB) *MemberHandler {
	return &MemberHandler{
		db:      db,
		checker: permissions.NewChecker(db),
	}
}

func (h *MemberHandler) RegisterRoutes(r chi.Router) {
	r.Get("/members", h.ListMembers)
	r.Patch("/members/{userID}", h.UpdateMember)
}

type memberResponse struct {
	ID          string  `json:"id"`
	Username    string  `json:"username"`
	DisplayName string  `json:"display_name"`
	Nickname    *string `json:"nickname"`
	Avatar      string  `json:"avatar"`
	Status      string  `json:"status"`
	StatusText  string  `json:"status_text"`
}

func (h *MemberHandler) ListMembers(w http.ResponseWriter, r *http.Request) {
	userID, ok := middleware.UserIDFromContext(r.Context())
	if !ok {
		http.Error(w, `{"error":"unauthorized"}`, http.StatusUnauthorized)
		return
	}

	serverID := chi.URLParam(r, "serverID")

	// Verify the caller is a member
	var exists bool
	err := h.db.QueryRowContext(r.Context(),
		`SELECT EXISTS(SELECT 1 FROM members WHERE user_id = $1 AND server_id = $2)`,
		userID, serverID).Scan(&exists)
	if err != nil || !exists {
		http.Error(w, `{"error":"not a member"}`, http.StatusForbidden)
		return
	}

	rows, err := h.db.QueryContext(r.Context(), `
		SELECT u.id, u.username, u.display_name, m.nickname, COALESCE(u.avatar, ''), u.status, COALESCE(u.status_text, '')
		FROM members m
		JOIN users u ON u.id = m.user_id
		WHERE m.server_id = $1
		ORDER BY u.username
	`, serverID)
	if err != nil {
		http.Error(w, `{"error":"server error"}`, http.StatusInternalServerError)
		return
	}
	defer rows.Close()

	members := make([]memberResponse, 0)
	for rows.Next() {
		var m memberResponse
		var nick sql.NullString
		if err := rows.Scan(&m.ID, &m.Username, &m.DisplayName, &nick, &m.Avatar, &m.Status, &m.StatusText); err != nil {
			continue
		}
		if nick.Valid {
			m.Nickname = &nick.String
		}
		members = append(members, m)
	}

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

type updateMemberRequest struct {
	Nickname *string `json:"nickname"`
}

func (h *MemberHandler) UpdateMember(w http.ResponseWriter, r *http.Request) {
	userID, ok := middleware.UserIDFromContext(r.Context())
	if !ok {
		http.Error(w, `{"error":"unauthorized"}`, http.StatusUnauthorized)
		return
	}

	serverID := chi.URLParam(r, "serverID")
	targetUserID := chi.URLParam(r, "userID")

	var req updateMemberRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
		return
	}

	if req.Nickname == nil {
		http.Error(w, `{"error":"nothing to update"}`, http.StatusBadRequest)
		return
	}

	// Check permissions:
	// - If self, need CHANGE_NICKNAME
	// - If other, need MANAGE_NICKNAMES
	var requiredPerm int64
	if userID == targetUserID {
		requiredPerm = permissions.CHANGE_NICKNAME
	} else {
		requiredPerm = permissions.MANAGE_NICKNAMES
	}

	allowed, err := h.checker.CheckPermission(r.Context(), serverID, userID, requiredPerm)
	if err != nil {
		http.Error(w, `{"error":"server error"}`, http.StatusInternalServerError)
		return
	}
	if !allowed {
		http.Error(w, `{"error":"forbidden"}`, http.StatusForbidden)
		return
	}

	// Update nickname in the database
	var nickVal sql.NullString
	if *req.Nickname != "" {
		nickVal = sql.NullString{String: *req.Nickname, Valid: true}
	} else {
		nickVal = sql.NullString{Valid: false} // NULL value clears the nickname
	}

	_, err = h.db.ExecContext(r.Context(), `
		UPDATE members
		SET nickname = $1
		WHERE user_id = $2 AND server_id = $3
	`, nickVal, targetUserID, serverID)
	if err != nil {
		http.Error(w, `{"error":"failed to update nickname"}`, http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusNoContent)
}
