package middleware

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/labstack/echo/v4"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/treytartt/honeydue-api/internal/config"
	"github.com/treytartt/honeydue-api/internal/models"
)

func TestAdminAuth_NoHeader_Returns401(t *testing.T) {
	cfg := &config.Config{
		Security: config.SecurityConfig{SecretKey: "test-secret"},
	}

	mw := AdminAuthMiddleware(cfg, nil)
	handler := mw(func(c echo.Context) error {
		return c.String(http.StatusOK, "ok")
	})

	e := echo.New()
	req := httptest.NewRequest(http.MethodGet, "/admin/test", nil)
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec)

	err := handler(c)
	require.NoError(t, err)
	assert.Equal(t, http.StatusUnauthorized, rec.Code)
	assert.Contains(t, rec.Body.String(), "Authorization required")
}

func TestAdminAuth_InvalidToken_Returns401(t *testing.T) {
	cfg := &config.Config{
		Security: config.SecurityConfig{SecretKey: "test-secret"},
	}

	mw := AdminAuthMiddleware(cfg, nil)
	handler := mw(func(c echo.Context) error {
		return c.String(http.StatusOK, "ok")
	})

	e := echo.New()
	req := httptest.NewRequest(http.MethodGet, "/admin/test", nil)
	req.Header.Set("Authorization", "Bearer invalid-jwt-token")
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec)

	err := handler(c)
	require.NoError(t, err)
	assert.Equal(t, http.StatusUnauthorized, rec.Code)
	assert.Contains(t, rec.Body.String(), "Invalid token")
}

func TestAdminAuth_TokenSchemeOnly_Returns401(t *testing.T) {
	cfg := &config.Config{
		Security: config.SecurityConfig{SecretKey: "test-secret"},
	}

	mw := AdminAuthMiddleware(cfg, nil)
	handler := mw(func(c echo.Context) error {
		return c.String(http.StatusOK, "ok")
	})

	e := echo.New()
	req := httptest.NewRequest(http.MethodGet, "/admin/test", nil)
	// "Token" scheme is not supported for admin auth, only "Bearer"
	req.Header.Set("Authorization", "Token some-token")
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec)

	err := handler(c)
	require.NoError(t, err)
	assert.Equal(t, http.StatusUnauthorized, rec.Code)
}

func TestRequireSuperAdmin_NoAdmin_Returns401(t *testing.T) {
	mw := RequireSuperAdmin()
	handler := mw(func(c echo.Context) error {
		return c.String(http.StatusOK, "ok")
	})

	e := echo.New()
	req := httptest.NewRequest(http.MethodGet, "/admin/test", nil)
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec)

	// No admin in context
	err := handler(c)
	require.NoError(t, err)
	assert.Equal(t, http.StatusUnauthorized, rec.Code)
}

func TestRequireSuperAdmin_WrongType_Returns401(t *testing.T) {
	mw := RequireSuperAdmin()
	handler := mw(func(c echo.Context) error {
		return c.String(http.StatusOK, "ok")
	})

	e := echo.New()
	req := httptest.NewRequest(http.MethodGet, "/admin/test", nil)
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec)

	// Wrong type in context
	c.Set(AdminUserKey, "not-an-admin")

	err := handler(c)
	require.NoError(t, err)
	assert.Equal(t, http.StatusUnauthorized, rec.Code)
}

func TestRequireSuperAdmin_NonSuperAdmin_Returns403(t *testing.T) {
	mw := RequireSuperAdmin()
	handler := mw(func(c echo.Context) error {
		return c.String(http.StatusOK, "ok")
	})

	e := echo.New()
	req := httptest.NewRequest(http.MethodGet, "/admin/test", nil)
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec)

	// Regular admin (not super admin)
	admin := &models.AdminUser{
		Email:    "admin@test.com",
		IsActive: true,
		Role:     models.AdminRoleAdmin,
	}
	c.Set(AdminUserKey, admin)

	err := handler(c)
	require.NoError(t, err)
	assert.Equal(t, http.StatusForbidden, rec.Code)
	assert.Contains(t, rec.Body.String(), "Super admin privileges required")
}

func TestRequireSuperAdmin_SuperAdmin_Passes(t *testing.T) {
	mw := RequireSuperAdmin()
	handler := mw(func(c echo.Context) error {
		return c.String(http.StatusOK, "ok")
	})

	e := echo.New()
	req := httptest.NewRequest(http.MethodGet, "/admin/test", nil)
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec)

	admin := &models.AdminUser{
		Email:    "superadmin@test.com",
		IsActive: true,
		Role:     models.AdminRoleSuperAdmin,
	}
	c.Set(AdminUserKey, admin)

	err := handler(c)
	require.NoError(t, err)
	assert.Equal(t, http.StatusOK, rec.Code)
}
