package handlers

import (
	"encoding/json"
	"net/http"
	"testing"
	"time"

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

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

func setupDeleteAccountHandler(t *testing.T) (*AuthHandler, *echo.Echo, *gorm.DB) {
	db := testutil.SetupTestDB(t)
	userRepo := repositories.NewUserRepository(db)
	cfg := &config.Config{
		Security: config.SecurityConfig{
			SecretKey:            "test-secret-key",
			PasswordResetExpiry:  15 * time.Minute,
			ConfirmationExpiry:   24 * time.Hour,
			MaxPasswordResetRate: 3,
		},
	}
	authService := services.NewAuthService(userRepo, cfg)
	handler := NewAuthHandler(authService, nil, nil)
	e := testutil.SetupTestRouter()
	return handler, e, db
}

func TestAuthHandler_DeleteAccount_EmailUser(t *testing.T) {
	handler, e, db := setupDeleteAccountHandler(t)

	user := testutil.CreateTestUser(t, db, "deletetest", "delete@test.com", "Password123")

	// Create profile for the user
	profile := &models.UserProfile{UserID: user.ID, Verified: true}
	require.NoError(t, db.Create(profile).Error)

	// Create auth token
	testutil.CreateTestToken(t, db, user.ID)

	authGroup := e.Group("/api/auth")
	authGroup.Use(testutil.MockAuthMiddleware(user))
	authGroup.DELETE("/account/", handler.DeleteAccount)

	t.Run("successful deletion with correct password", func(t *testing.T) {
		password := "Password123"
		req := map[string]interface{}{
			"password": password,
		}

		w := testutil.MakeRequest(e, "DELETE", "/api/auth/account/", req, "test-token")

		testutil.AssertStatusCode(t, w, http.StatusOK)

		var response map[string]interface{}
		err := json.Unmarshal(w.Body.Bytes(), &response)
		require.NoError(t, err)
		assert.Contains(t, response["message"], "Account deleted successfully")

		// Verify user is actually deleted
		var count int64
		db.Model(&models.User{}).Where("id = ?", user.ID).Count(&count)
		assert.Equal(t, int64(0), count)

		// Verify profile is deleted
		db.Model(&models.UserProfile{}).Where("user_id = ?", user.ID).Count(&count)
		assert.Equal(t, int64(0), count)

		// Verify auth token is deleted
		db.Model(&models.AuthToken{}).Where("user_id = ?", user.ID).Count(&count)
		assert.Equal(t, int64(0), count)
	})
}

func TestAuthHandler_DeleteAccount_WrongPassword(t *testing.T) {
	handler, e, db := setupDeleteAccountHandler(t)

	user := testutil.CreateTestUser(t, db, "wrongpw", "wrongpw@test.com", "Password123")

	authGroup := e.Group("/api/auth")
	authGroup.Use(testutil.MockAuthMiddleware(user))
	authGroup.DELETE("/account/", handler.DeleteAccount)

	t.Run("wrong password returns 401", func(t *testing.T) {
		wrongPw := "wrongpassword"
		req := map[string]interface{}{
			"password": wrongPw,
		}

		w := testutil.MakeRequest(e, "DELETE", "/api/auth/account/", req, "test-token")

		testutil.AssertStatusCode(t, w, http.StatusUnauthorized)
	})
}

func TestAuthHandler_DeleteAccount_MissingPassword(t *testing.T) {
	handler, e, db := setupDeleteAccountHandler(t)

	user := testutil.CreateTestUser(t, db, "nopw", "nopw@test.com", "Password123")

	authGroup := e.Group("/api/auth")
	authGroup.Use(testutil.MockAuthMiddleware(user))
	authGroup.DELETE("/account/", handler.DeleteAccount)

	t.Run("missing password returns 400", func(t *testing.T) {
		req := map[string]interface{}{}

		w := testutil.MakeRequest(e, "DELETE", "/api/auth/account/", req, "test-token")

		testutil.AssertStatusCode(t, w, http.StatusBadRequest)
	})
}

func TestAuthHandler_DeleteAccount_SocialAuthUser(t *testing.T) {
	handler, e, db := setupDeleteAccountHandler(t)

	user := testutil.CreateTestUser(t, db, "appleuser", "apple@test.com", "randompassword")

	// Create Apple social auth record
	appleAuth := &models.AppleSocialAuth{
		UserID:  user.ID,
		AppleID: "apple_sub_123",
		Email:   "apple@test.com",
	}
	require.NoError(t, db.Create(appleAuth).Error)

	// Create profile
	profile := &models.UserProfile{UserID: user.ID, Verified: true}
	require.NoError(t, db.Create(profile).Error)

	authGroup := e.Group("/api/auth")
	authGroup.Use(testutil.MockAuthMiddleware(user))
	authGroup.DELETE("/account/", handler.DeleteAccount)

	t.Run("successful deletion with DELETE confirmation", func(t *testing.T) {
		confirmation := "DELETE"
		req := map[string]interface{}{
			"confirmation": confirmation,
		}

		w := testutil.MakeRequest(e, "DELETE", "/api/auth/account/", req, "test-token")

		testutil.AssertStatusCode(t, w, http.StatusOK)

		// Verify user is deleted
		var count int64
		db.Model(&models.User{}).Where("id = ?", user.ID).Count(&count)
		assert.Equal(t, int64(0), count)

		// Verify apple auth is deleted
		db.Model(&models.AppleSocialAuth{}).Where("user_id = ?", user.ID).Count(&count)
		assert.Equal(t, int64(0), count)
	})
}

func TestAuthHandler_DeleteAccount_SocialAuthMissingConfirmation(t *testing.T) {
	handler, e, db := setupDeleteAccountHandler(t)

	user := testutil.CreateTestUser(t, db, "googleuser", "google@test.com", "randompassword")

	// Create Google social auth record
	googleAuth := &models.GoogleSocialAuth{
		UserID:   user.ID,
		GoogleID: "google_sub_456",
		Email:    "google@test.com",
	}
	require.NoError(t, db.Create(googleAuth).Error)

	authGroup := e.Group("/api/auth")
	authGroup.Use(testutil.MockAuthMiddleware(user))
	authGroup.DELETE("/account/", handler.DeleteAccount)

	t.Run("missing confirmation returns 400", func(t *testing.T) {
		req := map[string]interface{}{}

		w := testutil.MakeRequest(e, "DELETE", "/api/auth/account/", req, "test-token")

		testutil.AssertStatusCode(t, w, http.StatusBadRequest)
	})

	t.Run("wrong confirmation returns 400", func(t *testing.T) {
		wrongConfirmation := "delete"
		req := map[string]interface{}{
			"confirmation": wrongConfirmation,
		}

		w := testutil.MakeRequest(e, "DELETE", "/api/auth/account/", req, "test-token")

		testutil.AssertStatusCode(t, w, http.StatusBadRequest)
	})
}

func TestAuthHandler_DeleteAccount_Unauthenticated(t *testing.T) {
	handler, e, _ := setupDeleteAccountHandler(t)

	// No auth middleware - unauthenticated request
	e.DELETE("/api/auth/account/", handler.DeleteAccount)

	t.Run("unauthenticated request returns 401", func(t *testing.T) {
		req := map[string]interface{}{
			"password": "Password123",
		}

		w := testutil.MakeRequest(e, "DELETE", "/api/auth/account/", req, "")

		testutil.AssertStatusCode(t, w, http.StatusUnauthorized)
	})
}
