package handlers

import (
	"net/http"
	"testing"

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

// TestTaskHandler_NoAuth_Returns401 verifies that task handler endpoints return
// 401 Unauthorized when no auth user is set in the context (e.g., auth middleware
// misconfigured or bypassed). This is a regression test for P1-1 (SEC-19).
func TestTaskHandler_NoAuth_Returns401(t *testing.T) {
	db := testutil.SetupTestDB(t)
	taskRepo := repositories.NewTaskRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	taskService := services.NewTaskService(taskRepo, residenceRepo)
	handler := NewTaskHandler(taskService, nil)
	e := testutil.SetupTestRouter()

	// Register routes WITHOUT auth middleware
	e.GET("/api/tasks/", handler.ListTasks)
	e.GET("/api/tasks/:id/", handler.GetTask)
	e.POST("/api/tasks/", handler.CreateTask)
	e.PUT("/api/tasks/:id/", handler.UpdateTask)
	e.DELETE("/api/tasks/:id/", handler.DeleteTask)
	e.POST("/api/tasks/:id/cancel/", handler.CancelTask)
	e.POST("/api/tasks/:id/mark-in-progress/", handler.MarkInProgress)
	e.GET("/api/task-completions/", handler.ListCompletions)
	e.POST("/api/task-completions/", handler.CreateCompletion)

	tests := []struct {
		name   string
		method string
		path   string
	}{
		{"ListTasks", "GET", "/api/tasks/"},
		{"GetTask", "GET", "/api/tasks/1/"},
		{"CreateTask", "POST", "/api/tasks/"},
		{"UpdateTask", "PUT", "/api/tasks/1/"},
		{"DeleteTask", "DELETE", "/api/tasks/1/"},
		{"CancelTask", "POST", "/api/tasks/1/cancel/"},
		{"MarkInProgress", "POST", "/api/tasks/1/mark-in-progress/"},
		{"ListCompletions", "GET", "/api/task-completions/"},
		{"CreateCompletion", "POST", "/api/task-completions/"},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			w := testutil.MakeRequest(e, tt.method, tt.path, nil, "")
			testutil.AssertStatusCode(t, w, http.StatusUnauthorized)
		})
	}
}

// TestResidenceHandler_NoAuth_Returns401 verifies that residence handler endpoints
// return 401 Unauthorized when no auth user is set in the context.
func TestResidenceHandler_NoAuth_Returns401(t *testing.T) {
	db := testutil.SetupTestDB(t)
	residenceRepo := repositories.NewResidenceRepository(db)
	userRepo := repositories.NewUserRepository(db)
	cfg := &config.Config{}
	residenceService := services.NewResidenceService(residenceRepo, userRepo, cfg)
	handler := NewResidenceHandler(residenceService, nil, nil, true)
	e := testutil.SetupTestRouter()

	// Register routes WITHOUT auth middleware
	e.GET("/api/residences/", handler.ListResidences)
	e.GET("/api/residences/my/", handler.GetMyResidences)
	e.GET("/api/residences/summary/", handler.GetSummary)
	e.GET("/api/residences/:id/", handler.GetResidence)
	e.POST("/api/residences/", handler.CreateResidence)
	e.PUT("/api/residences/:id/", handler.UpdateResidence)
	e.DELETE("/api/residences/:id/", handler.DeleteResidence)
	e.POST("/api/residences/:id/generate-share-code/", handler.GenerateShareCode)
	e.POST("/api/residences/join-with-code/", handler.JoinWithCode)
	e.GET("/api/residences/:id/users/", handler.GetResidenceUsers)

	tests := []struct {
		name   string
		method string
		path   string
	}{
		{"ListResidences", "GET", "/api/residences/"},
		{"GetMyResidences", "GET", "/api/residences/my/"},
		{"GetSummary", "GET", "/api/residences/summary/"},
		{"GetResidence", "GET", "/api/residences/1/"},
		{"CreateResidence", "POST", "/api/residences/"},
		{"UpdateResidence", "PUT", "/api/residences/1/"},
		{"DeleteResidence", "DELETE", "/api/residences/1/"},
		{"GenerateShareCode", "POST", "/api/residences/1/generate-share-code/"},
		{"JoinWithCode", "POST", "/api/residences/join-with-code/"},
		{"GetResidenceUsers", "GET", "/api/residences/1/users/"},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			w := testutil.MakeRequest(e, tt.method, tt.path, nil, "")
			testutil.AssertStatusCode(t, w, http.StatusUnauthorized)
		})
	}
}

// TestNotificationHandler_NoAuth_Returns401 verifies that notification handler
// endpoints return 401 Unauthorized when no auth user is set in the context.
func TestNotificationHandler_NoAuth_Returns401(t *testing.T) {
	db := testutil.SetupTestDB(t)
	notificationRepo := repositories.NewNotificationRepository(db)
	notificationService := services.NewNotificationService(notificationRepo, nil)
	handler := NewNotificationHandler(notificationService)
	e := testutil.SetupTestRouter()

	// Register routes WITHOUT auth middleware
	e.GET("/api/notifications/", handler.ListNotifications)
	e.GET("/api/notifications/unread-count/", handler.GetUnreadCount)
	e.POST("/api/notifications/:id/read/", handler.MarkAsRead)
	e.POST("/api/notifications/mark-all-read/", handler.MarkAllAsRead)
	e.GET("/api/notifications/preferences/", handler.GetPreferences)
	e.PUT("/api/notifications/preferences/", handler.UpdatePreferences)
	e.POST("/api/notifications/devices/", handler.RegisterDevice)
	e.GET("/api/notifications/devices/", handler.ListDevices)

	tests := []struct {
		name   string
		method string
		path   string
	}{
		{"ListNotifications", "GET", "/api/notifications/"},
		{"GetUnreadCount", "GET", "/api/notifications/unread-count/"},
		{"MarkAsRead", "POST", "/api/notifications/1/read/"},
		{"MarkAllAsRead", "POST", "/api/notifications/mark-all-read/"},
		{"GetPreferences", "GET", "/api/notifications/preferences/"},
		{"UpdatePreferences", "PUT", "/api/notifications/preferences/"},
		{"RegisterDevice", "POST", "/api/notifications/devices/"},
		{"ListDevices", "GET", "/api/notifications/devices/"},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			w := testutil.MakeRequest(e, tt.method, tt.path, nil, "")
			testutil.AssertStatusCode(t, w, http.StatusUnauthorized)
		})
	}
}

// TestDocumentHandler_NoAuth_Returns401 verifies that document handler endpoints
// return 401 Unauthorized when no auth user is set in the context.
func TestDocumentHandler_NoAuth_Returns401(t *testing.T) {
	db := testutil.SetupTestDB(t)
	documentRepo := repositories.NewDocumentRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	documentService := services.NewDocumentService(documentRepo, residenceRepo)
	handler := NewDocumentHandler(documentService, nil)
	e := testutil.SetupTestRouter()

	// Register routes WITHOUT auth middleware
	e.GET("/api/documents/", handler.ListDocuments)
	e.GET("/api/documents/:id/", handler.GetDocument)
	e.GET("/api/documents/warranties/", handler.ListWarranties)
	e.POST("/api/documents/", handler.CreateDocument)
	e.PUT("/api/documents/:id/", handler.UpdateDocument)
	e.DELETE("/api/documents/:id/", handler.DeleteDocument)
	e.POST("/api/documents/:id/activate/", handler.ActivateDocument)
	e.POST("/api/documents/:id/deactivate/", handler.DeactivateDocument)

	tests := []struct {
		name   string
		method string
		path   string
	}{
		{"ListDocuments", "GET", "/api/documents/"},
		{"GetDocument", "GET", "/api/documents/1/"},
		{"ListWarranties", "GET", "/api/documents/warranties/"},
		{"CreateDocument", "POST", "/api/documents/"},
		{"UpdateDocument", "PUT", "/api/documents/1/"},
		{"DeleteDocument", "DELETE", "/api/documents/1/"},
		{"ActivateDocument", "POST", "/api/documents/1/activate/"},
		{"DeactivateDocument", "POST", "/api/documents/1/deactivate/"},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			w := testutil.MakeRequest(e, tt.method, tt.path, nil, "")
			testutil.AssertStatusCode(t, w, http.StatusUnauthorized)
		})
	}
}

// TestContractorHandler_NoAuth_Returns401 verifies that contractor handler endpoints
// return 401 Unauthorized when no auth user is set in the context.
func TestContractorHandler_NoAuth_Returns401(t *testing.T) {
	db := testutil.SetupTestDB(t)
	contractorRepo := repositories.NewContractorRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	contractorService := services.NewContractorService(contractorRepo, residenceRepo)
	handler := NewContractorHandler(contractorService)
	e := testutil.SetupTestRouter()

	// Register routes WITHOUT auth middleware
	e.GET("/api/contractors/", handler.ListContractors)
	e.GET("/api/contractors/:id/", handler.GetContractor)
	e.POST("/api/contractors/", handler.CreateContractor)
	e.PUT("/api/contractors/:id/", handler.UpdateContractor)
	e.DELETE("/api/contractors/:id/", handler.DeleteContractor)
	e.POST("/api/contractors/:id/toggle-favorite/", handler.ToggleFavorite)
	e.GET("/api/contractors/:id/tasks/", handler.GetContractorTasks)

	tests := []struct {
		name   string
		method string
		path   string
	}{
		{"ListContractors", "GET", "/api/contractors/"},
		{"GetContractor", "GET", "/api/contractors/1/"},
		{"CreateContractor", "POST", "/api/contractors/"},
		{"UpdateContractor", "PUT", "/api/contractors/1/"},
		{"DeleteContractor", "DELETE", "/api/contractors/1/"},
		{"ToggleFavorite", "POST", "/api/contractors/1/toggle-favorite/"},
		{"GetContractorTasks", "GET", "/api/contractors/1/tasks/"},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			w := testutil.MakeRequest(e, tt.method, tt.path, nil, "")
			testutil.AssertStatusCode(t, w, http.StatusUnauthorized)
		})
	}
}

// TestSubscriptionHandler_NoAuth_Returns401 verifies that subscription handler
// endpoints return 401 Unauthorized when no auth user is set in the context.
func TestSubscriptionHandler_NoAuth_Returns401(t *testing.T) {
	db := testutil.SetupTestDB(t)
	subscriptionRepo := repositories.NewSubscriptionRepository(db)
	residenceRepo := repositories.NewResidenceRepository(db)
	taskRepo := repositories.NewTaskRepository(db)
	contractorRepo := repositories.NewContractorRepository(db)
	documentRepo := repositories.NewDocumentRepository(db)
	subscriptionService := services.NewSubscriptionService(subscriptionRepo, residenceRepo, taskRepo, contractorRepo, documentRepo)
	handler := NewSubscriptionHandler(subscriptionService, nil)
	e := testutil.SetupTestRouter()

	// Register routes WITHOUT auth middleware
	e.GET("/api/subscription/", handler.GetSubscription)
	e.GET("/api/subscription/status/", handler.GetSubscriptionStatus)
	e.GET("/api/subscription/promotions/", handler.GetPromotions)
	e.POST("/api/subscription/purchase/", handler.ProcessPurchase)
	e.POST("/api/subscription/cancel/", handler.CancelSubscription)
	e.POST("/api/subscription/restore/", handler.RestoreSubscription)

	tests := []struct {
		name   string
		method string
		path   string
	}{
		{"GetSubscription", "GET", "/api/subscription/"},
		{"GetSubscriptionStatus", "GET", "/api/subscription/status/"},
		{"GetPromotions", "GET", "/api/subscription/promotions/"},
		{"ProcessPurchase", "POST", "/api/subscription/purchase/"},
		{"CancelSubscription", "POST", "/api/subscription/cancel/"},
		{"RestoreSubscription", "POST", "/api/subscription/restore/"},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			w := testutil.MakeRequest(e, tt.method, tt.path, nil, "")
			testutil.AssertStatusCode(t, w, http.StatusUnauthorized)
		})
	}
}

// TestMediaHandler_NoAuth_Returns401 verifies that media handler endpoints return
// 401 Unauthorized when no auth user is set in the context.
func TestMediaHandler_NoAuth_Returns401(t *testing.T) {
	handler := NewMediaHandler(nil, nil, nil, nil)
	e := testutil.SetupTestRouter()

	// Register routes WITHOUT auth middleware
	e.GET("/api/media/document/:id", handler.ServeDocument)
	e.GET("/api/media/document-image/:id", handler.ServeDocumentImage)
	e.GET("/api/media/completion-image/:id", handler.ServeCompletionImage)

	tests := []struct {
		name   string
		method string
		path   string
	}{
		{"ServeDocument", "GET", "/api/media/document/1"},
		{"ServeDocumentImage", "GET", "/api/media/document-image/1"},
		{"ServeCompletionImage", "GET", "/api/media/completion-image/1"},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			w := testutil.MakeRequest(e, tt.method, tt.path, nil, "")
			testutil.AssertStatusCode(t, w, http.StatusUnauthorized)
		})
	}
}

// TestUserHandler_NoAuth_Returns401 verifies that user handler endpoints return
// 401 Unauthorized when no auth user is set in the context.
func TestUserHandler_NoAuth_Returns401(t *testing.T) {
	db := testutil.SetupTestDB(t)
	userRepo := repositories.NewUserRepository(db)
	userService := services.NewUserService(userRepo)
	handler := NewUserHandler(userService)
	e := testutil.SetupTestRouter()

	// Register routes WITHOUT auth middleware
	e.GET("/api/users/", handler.ListUsers)
	e.GET("/api/users/:id/", handler.GetUser)
	e.GET("/api/users/profiles/", handler.ListProfiles)

	tests := []struct {
		name   string
		method string
		path   string
	}{
		{"ListUsers", "GET", "/api/users/"},
		{"GetUser", "GET", "/api/users/1/"},
		{"ListProfiles", "GET", "/api/users/profiles/"},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			w := testutil.MakeRequest(e, tt.method, tt.path, nil, "")
			testutil.AssertStatusCode(t, w, http.StatusUnauthorized)
		})
	}
}
