package handlers

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"strconv"
	"testing"
	"time"

	"github.com/Wikid82/charon/backend/internal/models"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

func setupUserHandler(t *testing.T) (*UserHandler, *gorm.DB) {
	// Use unique DB for each test to avoid pollution
	dbName := "file:" + t.Name() + "?mode=memory&cache=shared"
	db, err := gorm.Open(sqlite.Open(dbName), &gorm.Config{})
	require.NoError(t, err)
	db.AutoMigrate(&models.User{}, &models.Setting{})
	return NewUserHandler(db), db
}

func TestUserHandler_GetSetupStatus(t *testing.T) {
	handler, db := setupUserHandler(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.GET("/setup", handler.GetSetupStatus)

	// No users -> setup required
	req, _ := http.NewRequest("GET", "/setup", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)
	assert.Equal(t, http.StatusOK, w.Code)
	assert.Contains(t, w.Body.String(), "\"setupRequired\":true")

	// Create user -> setup not required
	db.Create(&models.User{Email: "test@example.com"})
	w = httptest.NewRecorder()
	r.ServeHTTP(w, req)
	assert.Equal(t, http.StatusOK, w.Code)
	assert.Contains(t, w.Body.String(), "\"setupRequired\":false")
}

func TestUserHandler_Setup(t *testing.T) {
	handler, _ := setupUserHandler(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.POST("/setup", handler.Setup)

	// 1. Invalid JSON (Before setup is done)
	w := httptest.NewRecorder()
	req, _ := http.NewRequest("POST", "/setup", bytes.NewBuffer([]byte("invalid json")))
	req.Header.Set("Content-Type", "application/json")
	r.ServeHTTP(w, req)
	assert.Equal(t, http.StatusBadRequest, w.Code)

	// 2. Valid Setup
	body := map[string]string{
		"name":     "Admin",
		"email":    "admin@example.com",
		"password": "password123",
	}
	jsonBody, _ := json.Marshal(body)
	req, _ = http.NewRequest("POST", "/setup", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w = httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusCreated, w.Code)
	assert.Contains(t, w.Body.String(), "Setup completed successfully")

	// 3. Try again -> should fail (already setup)
	w = httptest.NewRecorder()
	req, _ = http.NewRequest("POST", "/setup", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	r.ServeHTTP(w, req)
	assert.Equal(t, http.StatusForbidden, w.Code)
}

func TestUserHandler_Setup_DBError(t *testing.T) {
	// Can't easily mock DB error with sqlite memory unless we close it or something.
	// But we can try to insert duplicate email if we had a unique constraint and pre-seeded data,
	// but Setup checks if ANY user exists first.
	// So if we have a user, it returns Forbidden.
	// If we don't, it tries to create.
	// If we want Create to fail, maybe invalid data that passes binding but fails DB constraint?
	// User model has validation?
	// Let's try empty password if allowed by binding but rejected by DB?
	// Or very long string?
}

func TestUserHandler_RegenerateAPIKey(t *testing.T) {
	handler, db := setupUserHandler(t)

	user := &models.User{Email: "api@example.com"}
	db.Create(user)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("userID", user.ID)
		c.Next()
	})
	r.POST("/api-key", handler.RegenerateAPIKey)

	req, _ := http.NewRequest("POST", "/api-key", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
	var resp map[string]string
	json.Unmarshal(w.Body.Bytes(), &resp)
	assert.NotEmpty(t, resp["api_key"])

	// Verify DB
	var updatedUser models.User
	db.First(&updatedUser, user.ID)
	assert.Equal(t, resp["api_key"], updatedUser.APIKey)
}

func TestUserHandler_GetProfile(t *testing.T) {
	handler, db := setupUserHandler(t)

	user := &models.User{
		Email:  "profile@example.com",
		Name:   "Profile User",
		APIKey: "existing-key",
	}
	db.Create(user)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("userID", user.ID)
		c.Next()
	})
	r.GET("/profile", handler.GetProfile)

	req, _ := http.NewRequest("GET", "/profile", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
	var resp models.User
	json.Unmarshal(w.Body.Bytes(), &resp)
	assert.Equal(t, user.Email, resp.Email)
	assert.Equal(t, user.APIKey, resp.APIKey)
}

func TestUserHandler_RegisterRoutes(t *testing.T) {
	handler, _ := setupUserHandler(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	api := r.Group("/api")
	handler.RegisterRoutes(api)

	routes := r.Routes()
	expectedRoutes := map[string]string{
		"/api/setup":              "GET,POST",
		"/api/profile":            "GET",
		"/api/regenerate-api-key": "POST",
	}

	for path := range expectedRoutes {
		found := false
		for _, route := range routes {
			if route.Path == path {
				found = true
				break
			}
		}
		assert.True(t, found, "Route %s not found", path)
	}
}

func TestUserHandler_Errors(t *testing.T) {
	handler, db := setupUserHandler(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()

	// Middleware to simulate missing userID
	r.GET("/profile-no-auth", func(c *gin.Context) {
		// No userID set
		handler.GetProfile(c)
	})
	r.POST("/api-key-no-auth", func(c *gin.Context) {
		// No userID set
		handler.RegenerateAPIKey(c)
	})

	// Middleware to simulate non-existent user
	r.GET("/profile-not-found", func(c *gin.Context) {
		c.Set("userID", uint(99999))
		handler.GetProfile(c)
	})
	r.POST("/api-key-not-found", func(c *gin.Context) {
		c.Set("userID", uint(99999))
		handler.RegenerateAPIKey(c)
	})

	// Test Unauthorized
	req, _ := http.NewRequest("GET", "/profile-no-auth", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)
	assert.Equal(t, http.StatusUnauthorized, w.Code)

	req, _ = http.NewRequest("POST", "/api-key-no-auth", http.NoBody)
	w = httptest.NewRecorder()
	r.ServeHTTP(w, req)
	assert.Equal(t, http.StatusUnauthorized, w.Code)

	// Test Not Found (GetProfile)
	req, _ = http.NewRequest("GET", "/profile-not-found", http.NoBody)
	w = httptest.NewRecorder()
	r.ServeHTTP(w, req)
	assert.Equal(t, http.StatusNotFound, w.Code)

	// Test DB Error (RegenerateAPIKey) - Hard to mock DB error on update with sqlite memory,
	// but we can try to update a non-existent user which GORM Update might not treat as error unless we check RowsAffected.
	// The handler code: if err := h.DB.Model(&models.User{}).Where("id = ?", userID).Update("api_key", apiKey).Error; err != nil
	// Update on non-existent record usually returns nil error in GORM unless configured otherwise.
	// However, let's see if we can force an error by closing DB? No, shared DB.
	// We can drop the table?
	db.Migrator().DropTable(&models.User{})
	req, _ = http.NewRequest("POST", "/api-key-not-found", http.NoBody)
	w = httptest.NewRecorder()
	r.ServeHTTP(w, req)
	// If table missing, Update should fail
	assert.Equal(t, http.StatusInternalServerError, w.Code)
}

func TestUserHandler_UpdateProfile(t *testing.T) {
	handler, db := setupUserHandler(t)

	// Create user
	user := &models.User{
		UUID:   uuid.NewString(),
		Email:  "test@example.com",
		Name:   "Test User",
		APIKey: uuid.NewString(),
	}
	user.SetPassword("password123")
	db.Create(user)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("userID", user.ID)
		c.Next()
	})
	r.PUT("/profile", handler.UpdateProfile)

	// 1. Success - Name only
	t.Run("Success Name Only", func(t *testing.T) {
		body := map[string]string{
			"name":  "Updated Name",
			"email": "test@example.com",
		}
		jsonBody, _ := json.Marshal(body)
		req := httptest.NewRequest("PUT", "/profile", bytes.NewBuffer(jsonBody))
		req.Header.Set("Content-Type", "application/json")
		w := httptest.NewRecorder()
		r.ServeHTTP(w, req)

		assert.Equal(t, http.StatusOK, w.Code)
		var updatedUser models.User
		db.First(&updatedUser, user.ID)
		assert.Equal(t, "Updated Name", updatedUser.Name)
	})

	// 2. Success - Email change with password
	t.Run("Success Email Change", func(t *testing.T) {
		body := map[string]string{
			"name":             "Updated Name",
			"email":            "newemail@example.com",
			"current_password": "password123",
		}
		jsonBody, _ := json.Marshal(body)
		req := httptest.NewRequest("PUT", "/profile", bytes.NewBuffer(jsonBody))
		req.Header.Set("Content-Type", "application/json")
		w := httptest.NewRecorder()
		r.ServeHTTP(w, req)

		assert.Equal(t, http.StatusOK, w.Code)
		var updatedUser models.User
		db.First(&updatedUser, user.ID)
		assert.Equal(t, "newemail@example.com", updatedUser.Email)
	})

	// 3. Fail - Email change without password
	t.Run("Fail Email Change No Password", func(t *testing.T) {
		// Reset email
		db.Model(user).Update("email", "test@example.com")

		body := map[string]string{
			"name":  "Updated Name",
			"email": "another@example.com",
		}
		jsonBody, _ := json.Marshal(body)
		req := httptest.NewRequest("PUT", "/profile", bytes.NewBuffer(jsonBody))
		req.Header.Set("Content-Type", "application/json")
		w := httptest.NewRecorder()
		r.ServeHTTP(w, req)

		assert.Equal(t, http.StatusBadRequest, w.Code)
	})

	// 4. Fail - Email change wrong password
	t.Run("Fail Email Change Wrong Password", func(t *testing.T) {
		body := map[string]string{
			"name":             "Updated Name",
			"email":            "another@example.com",
			"current_password": "wrongpassword",
		}
		jsonBody, _ := json.Marshal(body)
		req := httptest.NewRequest("PUT", "/profile", bytes.NewBuffer(jsonBody))
		req.Header.Set("Content-Type", "application/json")
		w := httptest.NewRecorder()
		r.ServeHTTP(w, req)

		assert.Equal(t, http.StatusUnauthorized, w.Code)
	})

	// 5. Fail - Email already in use
	t.Run("Fail Email In Use", func(t *testing.T) {
		// Create another user
		otherUser := &models.User{
			UUID:   uuid.NewString(),
			Email:  "other@example.com",
			Name:   "Other User",
			APIKey: uuid.NewString(),
		}
		db.Create(otherUser)

		body := map[string]string{
			"name":  "Updated Name",
			"email": "other@example.com",
		}
		jsonBody, _ := json.Marshal(body)
		req := httptest.NewRequest("PUT", "/profile", bytes.NewBuffer(jsonBody))
		req.Header.Set("Content-Type", "application/json")
		w := httptest.NewRecorder()
		r.ServeHTTP(w, req)

		assert.Equal(t, http.StatusConflict, w.Code)
	})
}

func TestUserHandler_UpdateProfile_Errors(t *testing.T) {
	handler, _ := setupUserHandler(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()

	// 1. Unauthorized (no userID)
	r.PUT("/profile-no-auth", handler.UpdateProfile)
	req, _ := http.NewRequest("PUT", "/profile-no-auth", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)
	assert.Equal(t, http.StatusUnauthorized, w.Code)

	// Middleware for subsequent tests
	r.Use(func(c *gin.Context) {
		c.Set("userID", uint(999)) // Non-existent ID
		c.Next()
	})
	r.PUT("/profile", handler.UpdateProfile)

	// 2. BindJSON error
	req, _ = http.NewRequest("PUT", "/profile", bytes.NewBufferString("invalid"))
	req.Header.Set("Content-Type", "application/json")
	w = httptest.NewRecorder()
	r.ServeHTTP(w, req)
	assert.Equal(t, http.StatusBadRequest, w.Code)

	// 3. User not found
	body := map[string]string{"name": "New Name", "email": "new@example.com"}
	jsonBody, _ := json.Marshal(body)
	req, _ = http.NewRequest("PUT", "/profile", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w = httptest.NewRecorder()
	r.ServeHTTP(w, req)
	assert.Equal(t, http.StatusNotFound, w.Code)
}

// ============= User Management Tests (Admin functions) =============

func setupUserHandlerWithProxyHosts(t *testing.T) (*UserHandler, *gorm.DB) {
	dbName := "file:" + t.Name() + "?mode=memory&cache=shared"
	db, err := gorm.Open(sqlite.Open(dbName), &gorm.Config{})
	require.NoError(t, err)
	db.AutoMigrate(&models.User{}, &models.Setting{}, &models.ProxyHost{})
	return NewUserHandler(db), db
}

func TestUserHandler_ListUsers_NonAdmin(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "user")
		c.Next()
	})
	r.GET("/users", handler.ListUsers)

	req := httptest.NewRequest("GET", "/users", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusForbidden, w.Code)
}

func TestUserHandler_ListUsers_Admin(t *testing.T) {
	handler, db := setupUserHandlerWithProxyHosts(t)

	// Create users with unique API keys
	user1 := &models.User{UUID: uuid.NewString(), Email: "user1@example.com", Name: "User 1", APIKey: uuid.NewString()}
	user2 := &models.User{UUID: uuid.NewString(), Email: "user2@example.com", Name: "User 2", APIKey: uuid.NewString()}
	db.Create(user1)
	db.Create(user2)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	r.GET("/users", handler.ListUsers)

	req := httptest.NewRequest("GET", "/users", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
	var users []map[string]interface{}
	json.Unmarshal(w.Body.Bytes(), &users)
	assert.Len(t, users, 2)
}

func TestUserHandler_CreateUser_NonAdmin(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "user")
		c.Next()
	})
	r.POST("/users", handler.CreateUser)

	body := map[string]interface{}{
		"email":    "new@example.com",
		"name":     "New User",
		"password": "password123",
	}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("POST", "/users", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusForbidden, w.Code)
}

func TestUserHandler_CreateUser_Admin(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	r.POST("/users", handler.CreateUser)

	body := map[string]interface{}{
		"email":    "newuser@example.com",
		"name":     "New User",
		"password": "password123",
	}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("POST", "/users", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusCreated, w.Code)
}

func TestUserHandler_CreateUser_InvalidJSON(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	r.POST("/users", handler.CreateUser)

	req := httptest.NewRequest("POST", "/users", bytes.NewBufferString("invalid"))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestUserHandler_CreateUser_DuplicateEmail(t *testing.T) {
	handler, db := setupUserHandlerWithProxyHosts(t)

	existing := &models.User{UUID: uuid.NewString(), Email: "existing@example.com", Name: "Existing"}
	db.Create(existing)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	r.POST("/users", handler.CreateUser)

	body := map[string]interface{}{
		"email":    "existing@example.com",
		"name":     "New User",
		"password": "password123",
	}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("POST", "/users", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusConflict, w.Code)
}

func TestUserHandler_CreateUser_WithPermittedHosts(t *testing.T) {
	handler, db := setupUserHandlerWithProxyHosts(t)

	host := &models.ProxyHost{Name: "Host 1", DomainNames: "host1.example.com", Enabled: true}
	db.Create(host)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	r.POST("/users", handler.CreateUser)

	body := map[string]interface{}{
		"email":           "withhosts@example.com",
		"name":            "User With Hosts",
		"password":        "password123",
		"permission_mode": "deny_all",
		"permitted_hosts": []uint{host.ID},
	}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("POST", "/users", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusCreated, w.Code)
}

func TestUserHandler_GetUser_NonAdmin(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "user")
		c.Next()
	})
	r.GET("/users/:id", handler.GetUser)

	req := httptest.NewRequest("GET", "/users/1", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusForbidden, w.Code)
}

func TestUserHandler_GetUser_InvalidID(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	r.GET("/users/:id", handler.GetUser)

	req := httptest.NewRequest("GET", "/users/invalid", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestUserHandler_GetUser_NotFound(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	r.GET("/users/:id", handler.GetUser)

	req := httptest.NewRequest("GET", "/users/999", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusNotFound, w.Code)
}

func TestUserHandler_GetUser_Success(t *testing.T) {
	handler, db := setupUserHandlerWithProxyHosts(t)

	user := &models.User{UUID: uuid.NewString(), Email: "getuser@example.com", Name: "Get User"}
	db.Create(user)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	r.GET("/users/:id", handler.GetUser)

	req := httptest.NewRequest("GET", "/users/1", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
}

func TestUserHandler_UpdateUser_NonAdmin(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "user")
		c.Next()
	})
	r.PUT("/users/:id", handler.UpdateUser)

	body := map[string]interface{}{"name": "Updated"}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("PUT", "/users/1", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusForbidden, w.Code)
}

func TestUserHandler_UpdateUser_InvalidID(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	r.PUT("/users/:id", handler.UpdateUser)

	body := map[string]interface{}{"name": "Updated"}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("PUT", "/users/invalid", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestUserHandler_UpdateUser_InvalidJSON(t *testing.T) {
	handler, db := setupUserHandlerWithProxyHosts(t)

	// Create user first
	user := &models.User{UUID: uuid.NewString(), Email: "toupdate@example.com", Name: "To Update", APIKey: uuid.NewString()}
	db.Create(user)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	r.PUT("/users/:id", handler.UpdateUser)

	req := httptest.NewRequest("PUT", "/users/1", bytes.NewBufferString("invalid"))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestUserHandler_UpdateUser_NotFound(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	r.PUT("/users/:id", handler.UpdateUser)

	body := map[string]interface{}{"name": "Updated"}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("PUT", "/users/999", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusNotFound, w.Code)
}

func TestUserHandler_UpdateUser_Success(t *testing.T) {
	handler, db := setupUserHandlerWithProxyHosts(t)

	user := &models.User{UUID: uuid.NewString(), Email: "update@example.com", Name: "Original", Role: "user"}
	db.Create(user)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	r.PUT("/users/:id", handler.UpdateUser)

	body := map[string]interface{}{
		"name":    "Updated Name",
		"enabled": true,
	}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("PUT", "/users/1", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
}

func TestUserHandler_DeleteUser_NonAdmin(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "user")
		c.Next()
	})
	r.DELETE("/users/:id", handler.DeleteUser)

	req := httptest.NewRequest("DELETE", "/users/1", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusForbidden, w.Code)
}

func TestUserHandler_DeleteUser_InvalidID(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	r.DELETE("/users/:id", handler.DeleteUser)

	req := httptest.NewRequest("DELETE", "/users/invalid", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestUserHandler_DeleteUser_NotFound(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Set("userID", uint(1)) // Current user ID (different from target)
		c.Next()
	})
	r.DELETE("/users/:id", handler.DeleteUser)

	req := httptest.NewRequest("DELETE", "/users/999", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusNotFound, w.Code)
}

func TestUserHandler_DeleteUser_Success(t *testing.T) {
	handler, db := setupUserHandlerWithProxyHosts(t)

	user := &models.User{UUID: uuid.NewString(), Email: "delete@example.com", Name: "Delete Me"}
	db.Create(user)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Set("userID", uint(999)) // Different user
		c.Next()
	})
	r.DELETE("/users/:id", handler.DeleteUser)

	req := httptest.NewRequest("DELETE", "/users/1", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
}

func TestUserHandler_DeleteUser_CannotDeleteSelf(t *testing.T) {
	handler, db := setupUserHandlerWithProxyHosts(t)

	user := &models.User{UUID: uuid.NewString(), Email: "self@example.com", Name: "Self"}
	db.Create(user)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Set("userID", user.ID) // Same user
		c.Next()
	})
	r.DELETE("/users/:id", handler.DeleteUser)

	req := httptest.NewRequest("DELETE", "/users/1", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusForbidden, w.Code)
}

func TestUserHandler_UpdateUserPermissions_NonAdmin(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "user")
		c.Next()
	})
	r.PUT("/users/:id/permissions", handler.UpdateUserPermissions)

	body := map[string]interface{}{"permission_mode": "allow_all"}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("PUT", "/users/1/permissions", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusForbidden, w.Code)
}

func TestUserHandler_UpdateUserPermissions_InvalidID(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	r.PUT("/users/:id/permissions", handler.UpdateUserPermissions)

	body := map[string]interface{}{"permission_mode": "allow_all"}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("PUT", "/users/invalid/permissions", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestUserHandler_UpdateUserPermissions_InvalidJSON(t *testing.T) {
	handler, db := setupUserHandlerWithProxyHosts(t)

	// Create a user first
	user := &models.User{
		UUID:    uuid.NewString(),
		APIKey:  uuid.NewString(),
		Email:   "perms-invalid@example.com",
		Name:    "Perms Invalid Test",
		Role:    "user",
		Enabled: true,
	}
	db.Create(user)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	r.PUT("/users/:id/permissions", handler.UpdateUserPermissions)

	req := httptest.NewRequest("PUT", "/users/"+strconv.FormatUint(uint64(user.ID), 10)+"/permissions", bytes.NewBufferString("invalid"))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestUserHandler_UpdateUserPermissions_NotFound(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	r.PUT("/users/:id/permissions", handler.UpdateUserPermissions)

	body := map[string]interface{}{"permission_mode": "allow_all"}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("PUT", "/users/999/permissions", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusNotFound, w.Code)
}

func TestUserHandler_UpdateUserPermissions_Success(t *testing.T) {
	handler, db := setupUserHandlerWithProxyHosts(t)

	host := &models.ProxyHost{Name: "Host 1", DomainNames: "host1.example.com", Enabled: true}
	db.Create(host)

	user := &models.User{
		UUID:           uuid.NewString(),
		Email:          "perms@example.com",
		Name:           "Perms User",
		PermissionMode: models.PermissionModeAllowAll,
	}
	db.Create(user)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Next()
	})
	r.PUT("/users/:id/permissions", handler.UpdateUserPermissions)

	body := map[string]interface{}{
		"permission_mode": "deny_all",
		"permitted_hosts": []uint{host.ID},
	}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("PUT", "/users/1/permissions", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
}

func TestUserHandler_ValidateInvite_MissingToken(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.GET("/invite/validate", handler.ValidateInvite)

	req := httptest.NewRequest("GET", "/invite/validate", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestUserHandler_ValidateInvite_InvalidToken(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.GET("/invite/validate", handler.ValidateInvite)

	req := httptest.NewRequest("GET", "/invite/validate?token=invalidtoken", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusNotFound, w.Code)
}

func TestUserHandler_ValidateInvite_ExpiredToken(t *testing.T) {
	handler, db := setupUserHandlerWithProxyHosts(t)

	expiredTime := time.Now().Add(-24 * time.Hour) // Expired yesterday
	user := &models.User{
		UUID:          uuid.NewString(),
		Email:         "expired@example.com",
		Name:          "Expired Invite",
		InviteToken:   "expiredtoken123",
		InviteExpires: &expiredTime,
		InviteStatus:  "pending",
	}
	db.Create(user)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.GET("/invite/validate", handler.ValidateInvite)

	req := httptest.NewRequest("GET", "/invite/validate?token=expiredtoken123", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusGone, w.Code)
}

func TestUserHandler_ValidateInvite_AlreadyAccepted(t *testing.T) {
	handler, db := setupUserHandlerWithProxyHosts(t)

	expiresAt := time.Now().Add(24 * time.Hour)
	user := &models.User{
		UUID:          uuid.NewString(),
		Email:         "accepted@example.com",
		Name:          "Accepted Invite",
		InviteToken:   "acceptedtoken123",
		InviteExpires: &expiresAt,
		InviteStatus:  "accepted",
	}
	db.Create(user)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.GET("/invite/validate", handler.ValidateInvite)

	req := httptest.NewRequest("GET", "/invite/validate?token=acceptedtoken123", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusConflict, w.Code)
}

func TestUserHandler_ValidateInvite_Success(t *testing.T) {
	handler, db := setupUserHandlerWithProxyHosts(t)

	expiresAt := time.Now().Add(24 * time.Hour)
	user := &models.User{
		UUID:          uuid.NewString(),
		Email:         "valid@example.com",
		Name:          "Valid Invite",
		InviteToken:   "validtoken123",
		InviteExpires: &expiresAt,
		InviteStatus:  "pending",
	}
	db.Create(user)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.GET("/invite/validate", handler.ValidateInvite)

	req := httptest.NewRequest("GET", "/invite/validate?token=validtoken123", http.NoBody)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
	var resp map[string]interface{}
	json.Unmarshal(w.Body.Bytes(), &resp)
	assert.Equal(t, "valid@example.com", resp["email"])
}

func TestUserHandler_AcceptInvite_InvalidJSON(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.POST("/invite/accept", handler.AcceptInvite)

	req := httptest.NewRequest("POST", "/invite/accept", bytes.NewBufferString("invalid"))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestUserHandler_AcceptInvite_InvalidToken(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.POST("/invite/accept", handler.AcceptInvite)

	body := map[string]string{
		"token":    "invalidtoken",
		"name":     "Test User",
		"password": "password123",
	}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("POST", "/invite/accept", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusNotFound, w.Code)
}

func TestUserHandler_AcceptInvite_Success(t *testing.T) {
	handler, db := setupUserHandlerWithProxyHosts(t)

	expiresAt := time.Now().Add(24 * time.Hour)
	user := &models.User{
		UUID:          uuid.NewString(),
		Email:         "accept@example.com",
		Name:          "Accept User",
		InviteToken:   "accepttoken123",
		InviteExpires: &expiresAt,
		InviteStatus:  "pending",
	}
	db.Create(user)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.POST("/invite/accept", handler.AcceptInvite)

	body := map[string]string{
		"token":    "accepttoken123",
		"password": "newpassword123",
		"name":     "Accepted User",
	}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("POST", "/invite/accept", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)

	// Verify user was updated
	var updated models.User
	db.First(&updated, user.ID)
	assert.Equal(t, "accepted", updated.InviteStatus)
	assert.True(t, updated.Enabled)
}

func TestGenerateSecureToken(t *testing.T) {
	token, err := generateSecureToken(32)
	assert.NoError(t, err)
	assert.Len(t, token, 64) // 32 bytes = 64 hex chars
	assert.Regexp(t, "^[a-f0-9]+$", token)

	// Ensure uniqueness
	token2, err := generateSecureToken(32)
	assert.NoError(t, err)
	assert.NotEqual(t, token, token2)
}

func TestUserHandler_InviteUser_NonAdmin(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "user")
		c.Set("userID", uint(1))
		c.Next()
	})
	r.POST("/users/invite", handler.InviteUser)

	body := map[string]string{"email": "invitee@example.com"}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("POST", "/users/invite", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusForbidden, w.Code)
}

func TestUserHandler_InviteUser_InvalidJSON(t *testing.T) {
	handler, _ := setupUserHandlerWithProxyHosts(t)
	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Set("userID", uint(1))
		c.Next()
	})
	r.POST("/users/invite", handler.InviteUser)

	req := httptest.NewRequest("POST", "/users/invite", bytes.NewBufferString("invalid"))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestUserHandler_InviteUser_DuplicateEmail(t *testing.T) {
	handler, db := setupUserHandlerWithProxyHosts(t)

	// Create existing user
	existingUser := &models.User{
		UUID:   uuid.NewString(),
		APIKey: uuid.NewString(),
		Email:  "existing@example.com",
	}
	db.Create(existingUser)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Set("userID", uint(1))
		c.Next()
	})
	r.POST("/users/invite", handler.InviteUser)

	body := map[string]string{"email": "existing@example.com"}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("POST", "/users/invite", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusConflict, w.Code)
}

func TestUserHandler_InviteUser_Success(t *testing.T) {
	handler, db := setupUserHandlerWithProxyHosts(t)

	// Create admin user
	admin := &models.User{
		UUID:   uuid.NewString(),
		APIKey: uuid.NewString(),
		Email:  "admin@example.com",
		Role:   "admin",
	}
	db.Create(admin)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Set("userID", admin.ID)
		c.Next()
	})
	r.POST("/users/invite", handler.InviteUser)

	body := map[string]interface{}{
		"email": "newinvite@example.com",
		"role":  "user",
	}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("POST", "/users/invite", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusCreated, w.Code)

	var resp map[string]interface{}
	json.Unmarshal(w.Body.Bytes(), &resp)
	assert.NotEmpty(t, resp["invite_token"])
	// email_sent is false because no SMTP is configured
	assert.Equal(t, false, resp["email_sent"].(bool))

	// Verify user was created
	var user models.User
	db.Where("email = ?", "newinvite@example.com").First(&user)
	assert.Equal(t, "pending", user.InviteStatus)
	assert.False(t, user.Enabled)
}

func TestUserHandler_InviteUser_WithPermittedHosts(t *testing.T) {
	handler, db := setupUserHandlerWithProxyHosts(t)

	// Create admin user
	admin := &models.User{
		UUID:   uuid.NewString(),
		APIKey: uuid.NewString(),
		Email:  "admin-perm@example.com",
		Role:   "admin",
	}
	db.Create(admin)

	// Create proxy host
	host := &models.ProxyHost{
		UUID:        uuid.NewString(),
		Name:        "Test Host",
		DomainNames: "test.example.com",
	}
	db.Create(host)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.Use(func(c *gin.Context) {
		c.Set("role", "admin")
		c.Set("userID", admin.ID)
		c.Next()
	})
	r.POST("/users/invite", handler.InviteUser)

	body := map[string]interface{}{
		"email":           "invitee-perms@example.com",
		"permission_mode": "deny_all",
		"permitted_hosts": []uint{host.ID},
	}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("POST", "/users/invite", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusCreated, w.Code)

	// Verify user has permitted hosts
	var user models.User
	db.Preload("PermittedHosts").Where("email = ?", "invitee-perms@example.com").First(&user)
	assert.Len(t, user.PermittedHosts, 1)
	assert.Equal(t, models.PermissionModeDenyAll, user.PermissionMode)
}

func TestGetBaseURL(t *testing.T) {
	gin.SetMode(gin.TestMode)

	// Test with X-Forwarded-Proto header
	r := gin.New()
	r.GET("/test", func(c *gin.Context) {
		url := getBaseURL(c)
		c.String(200, url)
	})

	req := httptest.NewRequest("GET", "/test", http.NoBody)
	req.Host = "example.com"
	req.Header.Set("X-Forwarded-Proto", "https")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, "https://example.com", w.Body.String())
}

func TestGetAppName(t *testing.T) {
	db, err := gorm.Open(sqlite.Open("file:appname?mode=memory&cache=shared"), &gorm.Config{})
	require.NoError(t, err)
	db.AutoMigrate(&models.Setting{})

	// Test default
	name := getAppName(db)
	assert.Equal(t, "Charon", name)

	// Test with custom setting
	db.Create(&models.Setting{Key: "app_name", Value: "CustomApp"})
	name = getAppName(db)
	assert.Equal(t, "CustomApp", name)
}

func TestUserHandler_AcceptInvite_ExpiredToken(t *testing.T) {
	handler, db := setupUserHandlerWithProxyHosts(t)

	// Create user with expired invite
	expired := time.Now().Add(-24 * time.Hour)
	user := &models.User{
		UUID:          uuid.NewString(),
		APIKey:        uuid.NewString(),
		Email:         "expired-invite@example.com",
		InviteToken:   "expiredtoken123",
		InviteExpires: &expired,
		InviteStatus:  "pending",
	}
	db.Create(user)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.POST("/invite/accept", handler.AcceptInvite)

	body := map[string]string{
		"token":    "expiredtoken123",
		"name":     "Expired User",
		"password": "password123",
	}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("POST", "/invite/accept", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusGone, w.Code)
}

func TestUserHandler_AcceptInvite_AlreadyAccepted(t *testing.T) {
	handler, db := setupUserHandlerWithProxyHosts(t)

	expires := time.Now().Add(24 * time.Hour)
	user := &models.User{
		UUID:          uuid.NewString(),
		APIKey:        uuid.NewString(),
		Email:         "accepted-already@example.com",
		InviteToken:   "acceptedtoken123",
		InviteExpires: &expires,
		InviteStatus:  "accepted",
	}
	db.Create(user)

	gin.SetMode(gin.TestMode)
	r := gin.New()
	r.POST("/invite/accept", handler.AcceptInvite)

	body := map[string]string{
		"token":    "acceptedtoken123",
		"name":     "Already Accepted",
		"password": "password123",
	}
	jsonBody, _ := json.Marshal(body)
	req := httptest.NewRequest("POST", "/invite/accept", bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)

	assert.Equal(t, http.StatusConflict, w.Code)
}
