package auth

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

	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/require"
)

func TestSessionLoginRejectsValidationBeforeStore(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name       string
		body       string
		wantStatus int
		wantBody   string
	}{
		{
			name:       "invalid json",
			body:       `{`,
			wantStatus: http.StatusBadRequest,
			wantBody:   "Invalid request body",
		},
		{
			name:       "invalid login identifier",
			body:       `{"email":"not-an-email","password":"secret"}`,
			wantStatus: http.StatusBadRequest,
			wantBody:   "invalid mobile number",
		},
		{
			name:       "empty password",
			body:       `{"email":"user@example.com","password":"   "}`,
			wantStatus: http.StatusBadRequest,
			wantBody:   "password is required",
		},
	}

	handler := &SessionHandler{}
	router := gin.New()
	router.POST("/api/v1/auth/login", handler.Login)

	for _, tt := range tests {
		tt := tt
		t.Run(tt.name, func(t *testing.T) {
			t.Parallel()

			recorder := httptest.NewRecorder()
			request := httptest.NewRequest(http.MethodPost, "/api/v1/auth/login", bytes.NewBufferString(tt.body))
			router.ServeHTTP(recorder, request)

			require.Equal(t, tt.wantStatus, recorder.Code)
			require.Contains(t, recorder.Body.String(), tt.wantBody)
		})
	}
}

func TestSessionLoginReturnsUnavailableWhenPasswordAuthDisabled(t *testing.T) {
	t.Parallel()

	handler := &SessionHandler{passwordAuthDisabled: true}
	router := gin.New()
	router.POST("/api/v1/auth/login", handler.Login)

	recorder := httptest.NewRecorder()
	request := httptest.NewRequest(http.MethodPost, "/api/v1/auth/login", bytes.NewBufferString(`{"email":"user@example.com","password":"secret"}`))
	router.ServeHTTP(recorder, request)

	require.Equal(t, http.StatusServiceUnavailable, recorder.Code)
	require.Contains(t, recorder.Body.String(), "Password auth is disabled")
}

func TestSessionRefreshRejectsValidationBeforeStore(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name     string
		body     string
		wantBody string
	}{
		{
			name:     "invalid body",
			body:     `{`,
			wantBody: "Invalid request body",
		},
		{
			name:     "missing refresh token",
			body:     `{}`,
			wantBody: "refreshToken is required",
		},
	}

	handler := &SessionHandler{}
	router := gin.New()
	router.POST("/api/v1/auth/refresh", handler.Refresh)

	for _, tt := range tests {
		tt := tt
		t.Run(tt.name, func(t *testing.T) {
			t.Parallel()

			recorder := httptest.NewRecorder()
			request := httptest.NewRequest(http.MethodPost, "/api/v1/auth/refresh", bytes.NewBufferString(tt.body))
			router.ServeHTTP(recorder, request)

			require.Equal(t, http.StatusBadRequest, recorder.Code)
			require.Contains(t, recorder.Body.String(), tt.wantBody)
		})
	}
}

func TestSessionLogoutAllowsMissingTokens(t *testing.T) {
	t.Parallel()

	handler := &SessionHandler{}
	router := gin.New()
	router.POST("/api/v1/auth/logout", handler.Logout)

	recorder := httptest.NewRecorder()
	request := httptest.NewRequest(http.MethodPost, "/api/v1/auth/logout", bytes.NewBufferString(`{}`))
	router.ServeHTTP(recorder, request)

	require.Equal(t, http.StatusOK, recorder.Code)
	require.JSONEq(t, `{}`, recorder.Body.String())
}
