package main

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

	"github.com/google/uuid"
	"github.com/stretchr/testify/assert"
)

// TestLibraryManagementEndpoints tests library management operations
func TestLibraryManagementEndpoints(t *testing.T) {
	libraryID := uuid.New()

	t.Run("POST /api/libraries - Create library without admin role", func(t *testing.T) {
		payload := map[string]interface{}{
			"name":        "New Library",
			"description": "Test description",
			"type":        "ebooks",
		}
		jsonData, _ := json.Marshal(payload)

		req := httptest.NewRequest("POST", "/api/libraries", bytes.NewBuffer(jsonData))
		req.Header.Set("Content-Type", "application/json")
		req.Header.Set("Authorization", "Bearer user-token")
		req.Header.Set("X-User-Role", "user")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			userRole := r.Header.Get("X-User-Role")
			if userRole != "admin" {
				w.WriteHeader(http.StatusForbidden)
				w.Write([]byte(`{"error":"admin access required"}`))
				return
			}

			w.WriteHeader(http.StatusCreated)
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusForbidden, rr.Code)
	})

	t.Run("POST /api/libraries - Create library with invalid type", func(t *testing.T) {
		payload := map[string]interface{}{
			"name":        "New Library",
			"description": "Test description",
			"type":        "invalid-type",
		}
		jsonData, _ := json.Marshal(payload)

		req := httptest.NewRequest("POST", "/api/libraries", bytes.NewBuffer(jsonData))
		req.Header.Set("Content-Type", "application/json")
		req.Header.Set("Authorization", "Bearer admin-token")
		req.Header.Set("X-User-Role", "admin")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			var req map[string]interface{}
			if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
				w.WriteHeader(http.StatusBadRequest)
				w.Write([]byte(`{"error":"invalid request"}`))
				return
			}

			libType := req["type"].(string)
			if libType != "ebooks" && libType != "comics" && libType != "manga" {
				w.WriteHeader(http.StatusBadRequest)
				w.Write([]byte(`{"error":"invalid library type"}`))
				return
			}

			w.WriteHeader(http.StatusCreated)
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusBadRequest, rr.Code)
	})

	t.Run("POST /api/libraries - Create library with missing required fields", func(t *testing.T) {
		payload := map[string]interface{}{
			"description": "Test description",
		}
		jsonData, _ := json.Marshal(payload)

		req := httptest.NewRequest("POST", "/api/libraries", bytes.NewBuffer(jsonData))
		req.Header.Set("Content-Type", "application/json")
		req.Header.Set("Authorization", "Bearer admin-token")
		req.Header.Set("X-User-Role", "admin")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			var req map[string]interface{}
			if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
				w.WriteHeader(http.StatusBadRequest)
				w.Write([]byte(`{"error":"invalid request"}`))
				return
			}

			if _, ok := req["name"]; !ok {
				w.WriteHeader(http.StatusBadRequest)
				w.Write([]byte(`{"error":"name is required"}`))
				return
			}

			if _, ok := req["type"]; !ok {
				w.WriteHeader(http.StatusBadRequest)
				w.Write([]byte(`{"error":"type is required"}`))
				return
			}

			w.WriteHeader(http.StatusCreated)
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusBadRequest, rr.Code)
	})

	t.Run("GET /api/libraries/:id - Get library with invalid UUID", func(t *testing.T) {
		req := httptest.NewRequest("GET", "/api/libraries/invalid-uuid", nil)
		req.Header.Set("Authorization", "Bearer admin-token")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte(`{"error":"invalid library id"}`))
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusBadRequest, rr.Code)
	})

	t.Run("GET /api/libraries/:id - Get non-existent library", func(t *testing.T) {
		req := httptest.NewRequest("GET", "/api/libraries/"+uuid.New().String(), nil)
		req.Header.Set("Authorization", "Bearer admin-token")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.WriteHeader(http.StatusNotFound)
			w.Write([]byte(`{"error":"library not found"}`))
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusNotFound, rr.Code)
	})

	t.Run("PUT /api/libraries/:id - Update library without admin role", func(t *testing.T) {
		payload := map[string]interface{}{
			"name":        "Updated Library",
			"description": "Updated description",
		}
		jsonData, _ := json.Marshal(payload)

		req := httptest.NewRequest("PUT", "/api/libraries/"+libraryID.String(), bytes.NewBuffer(jsonData))
		req.Header.Set("Content-Type", "application/json")
		req.Header.Set("Authorization", "Bearer user-token")
		req.Header.Set("X-User-Role", "user")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			userRole := r.Header.Get("X-User-Role")
			if userRole != "admin" {
				w.WriteHeader(http.StatusForbidden)
				w.Write([]byte(`{"error":"admin access required"}`))
				return
			}

			w.WriteHeader(http.StatusOK)
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusForbidden, rr.Code)
	})

	t.Run("DELETE /api/libraries/:id - Delete library without admin role", func(t *testing.T) {
		req := httptest.NewRequest("DELETE", "/api/libraries/"+libraryID.String(), nil)
		req.Header.Set("Authorization", "Bearer user-token")
		req.Header.Set("X-User-Role", "user")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			userRole := r.Header.Get("X-User-Role")
			if userRole != "admin" {
				w.WriteHeader(http.StatusForbidden)
				w.Write([]byte(`{"error":"admin access required"}`))
				return
			}

			w.WriteHeader(http.StatusNoContent)
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusForbidden, rr.Code)
	})

	t.Run("DELETE /api/libraries/:id - Delete library with invalid UUID", func(t *testing.T) {
		req := httptest.NewRequest("DELETE", "/api/libraries/invalid-uuid", nil)
		req.Header.Set("Authorization", "Bearer admin-token")
		req.Header.Set("X-User-Role", "admin")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte(`{"error":"invalid library id"}`))
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusBadRequest, rr.Code)
	})
}

// TestLibraryFolders tests library folder management
func TestLibraryFolders(t *testing.T) {
	libraryID := uuid.New()

	t.Run("POST /api/libraries/:id/folders - Add folder without admin role", func(t *testing.T) {
		payload := map[string]interface{}{
			"folder_path": "/path/to/folder",
		}
		jsonData, _ := json.Marshal(payload)

		req := httptest.NewRequest("POST", "/api/libraries/"+libraryID.String()+"/folders", bytes.NewBuffer(jsonData))
		req.Header.Set("Content-Type", "application/json")
		req.Header.Set("Authorization", "Bearer user-token")
		req.Header.Set("X-User-Role", "user")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			userRole := r.Header.Get("X-User-Role")
			if userRole != "admin" {
				w.WriteHeader(http.StatusForbidden)
				w.Write([]byte(`{"error":"admin access required"}`))
				return
			}

			w.WriteHeader(http.StatusCreated)
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusForbidden, rr.Code)
	})

	t.Run("POST /api/libraries/:id/folders - Add folder with invalid library ID", func(t *testing.T) {
		payload := map[string]interface{}{
			"folder_path": "/path/to/folder",
		}
		jsonData, _ := json.Marshal(payload)

		req := httptest.NewRequest("POST", "/api/libraries/invalid-uuid/folders", bytes.NewBuffer(jsonData))
		req.Header.Set("Content-Type", "application/json")
		req.Header.Set("Authorization", "Bearer admin-token")
		req.Header.Set("X-User-Role", "admin")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte(`{"error":"invalid library id"}`))
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusBadRequest, rr.Code)
	})

	t.Run("POST /api/libraries/:id/folders - Add folder with missing path", func(t *testing.T) {
		payload := map[string]interface{}{}
		jsonData, _ := json.Marshal(payload)

		req := httptest.NewRequest("POST", "/api/libraries/"+libraryID.String()+"/folders", bytes.NewBuffer(jsonData))
		req.Header.Set("Content-Type", "application/json")
		req.Header.Set("Authorization", "Bearer admin-token")
		req.Header.Set("X-User-Role", "admin")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			var req map[string]interface{}
			if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
				w.WriteHeader(http.StatusBadRequest)
				w.Write([]byte(`{"error":"invalid request"}`))
				return
			}

			if _, ok := req["folder_path"]; !ok {
				w.WriteHeader(http.StatusBadRequest)
				w.Write([]byte(`{"error":"folder_path is required"}`))
				return
			}

			w.WriteHeader(http.StatusCreated)
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusBadRequest, rr.Code)
	})

	t.Run("GET /api/libraries/:id/folders - Get folders without admin role", func(t *testing.T) {
		req := httptest.NewRequest("GET", "/api/libraries/"+libraryID.String()+"/folders", nil)
		req.Header.Set("Authorization", "Bearer user-token")
		req.Header.Set("X-User-Role", "user")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			userRole := r.Header.Get("X-User-Role")
			if userRole != "admin" {
				w.WriteHeader(http.StatusForbidden)
				w.Write([]byte(`{"error":"admin access required"}`))
				return
			}

			w.WriteHeader(http.StatusOK)
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusForbidden, rr.Code)
	})

	t.Run("DELETE /api/libraries/:id/folders - Delete folder without admin role", func(t *testing.T) {
		payload := map[string]interface{}{
			"folder_path": "/path/to/folder",
		}
		jsonData, _ := json.Marshal(payload)

		req := httptest.NewRequest("DELETE", "/api/libraries/"+libraryID.String()+"/folders", bytes.NewBuffer(jsonData))
		req.Header.Set("Content-Type", "application/json")
		req.Header.Set("Authorization", "Bearer user-token")
		req.Header.Set("X-User-Role", "user")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			userRole := r.Header.Get("X-User-Role")
			if userRole != "admin" {
				w.WriteHeader(http.StatusForbidden)
				w.Write([]byte(`{"error":"admin access required"}`))
				return
			}

			w.WriteHeader(http.StatusNoContent)
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusForbidden, rr.Code)
	})
}

// TestLibraryVisibility tests library visibility controls
func TestLibraryVisibility(t *testing.T) {
	libraryID := uuid.New()
	userID := uuid.New()

	t.Run("POST /api/libraries/visibility - Set visibility without auth", func(t *testing.T) {
		payload := map[string]interface{}{
			"library_id": libraryID.String(),
			"is_visible": true,
		}
		jsonData, _ := json.Marshal(payload)

		req := httptest.NewRequest("POST", "/api/libraries/visibility", bytes.NewBuffer(jsonData))
		req.Header.Set("Content-Type", "application/json")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			authHeader := r.Header.Get("Authorization")
			if authHeader == "" {
				w.WriteHeader(http.StatusUnauthorized)
				w.Write([]byte(`{"message":"missing or malformed jwt"}`))
				return
			}

			w.WriteHeader(http.StatusOK)
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusUnauthorized, rr.Code)
	})

	t.Run("POST /api/libraries/visibility - Set visibility with invalid library ID", func(t *testing.T) {
		payload := map[string]interface{}{
			"library_id": "invalid-uuid",
			"is_visible": true,
		}
		jsonData, _ := json.Marshal(payload)

		req := httptest.NewRequest("POST", "/api/libraries/visibility", bytes.NewBuffer(jsonData))
		req.Header.Set("Content-Type", "application/json")
		req.Header.Set("Authorization", "Bearer valid-token")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			var req map[string]interface{}
			if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
				w.WriteHeader(http.StatusBadRequest)
				w.Write([]byte(`{"error":"invalid request"}`))
				return
			}

			libID := req["library_id"].(string)
			if _, err := uuid.Parse(libID); err != nil {
				w.WriteHeader(http.StatusBadRequest)
				w.Write([]byte(`{"error":"invalid library id"}`))
				return
			}

			w.WriteHeader(http.StatusOK)
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusBadRequest, rr.Code)
	})

	t.Run("POST /api/libraries/visibility - Set visibility successfully", func(t *testing.T) {
		payload := map[string]interface{}{
			"library_id": libraryID.String(),
			"is_visible": true,
		}
		jsonData, _ := json.Marshal(payload)

		req := httptest.NewRequest("POST", "/api/libraries/visibility", bytes.NewBuffer(jsonData))
		req.Header.Set("Content-Type", "application/json")
		req.Header.Set("Authorization", "Bearer valid-token")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			visibility := map[string]interface{}{
				"id":         uuid.New().String(),
				"user_id":    userID.String(),
				"library_id": libraryID.String(),
				"is_visible": true,
			}
			w.WriteHeader(http.StatusOK)
			json.NewEncoder(w).Encode(visibility)
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusOK, rr.Code)
	})

	t.Run("GET /api/libraries/visible - Get visible libraries without auth", func(t *testing.T) {
		req := httptest.NewRequest("GET", "/api/libraries/visible", nil)
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			authHeader := r.Header.Get("Authorization")
			if authHeader == "" {
				w.WriteHeader(http.StatusUnauthorized)
				w.Write([]byte(`{"message":"missing or malformed jwt"}`))
				return
			}

			w.WriteHeader(http.StatusOK)
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusUnauthorized, rr.Code)
	})

	t.Run("GET /api/libraries/visible - Get visible libraries with auth", func(t *testing.T) {
		req := httptest.NewRequest("GET", "/api/libraries/visible", nil)
		req.Header.Set("Authorization", "Bearer valid-token")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			libraries := []map[string]interface{}{
				{
					"id":         libraryID.String(),
					"name":       "Visible Library",
					"is_visible": true,
				},
			}
			w.WriteHeader(http.StatusOK)
			json.NewEncoder(w).Encode(libraries)
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusOK, rr.Code)
	})
}

// TestLibraryStats tests library statistics
func TestLibraryStats(t *testing.T) {
	libraryID := uuid.New()

	t.Run("GET /api/libraries/:id/stats - Get stats without admin role", func(t *testing.T) {
		req := httptest.NewRequest("GET", "/api/libraries/"+libraryID.String()+"/stats", nil)
		req.Header.Set("Authorization", "Bearer user-token")
		req.Header.Set("X-User-Role", "user")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			userRole := r.Header.Get("X-User-Role")
			if userRole != "admin" {
				w.WriteHeader(http.StatusForbidden)
				w.Write([]byte(`{"error":"admin access required"}`))
				return
			}

			w.WriteHeader(http.StatusOK)
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusForbidden, rr.Code)
	})

	t.Run("GET /api/libraries/:id/stats - Get stats with invalid library ID", func(t *testing.T) {
		req := httptest.NewRequest("GET", "/api/libraries/invalid-uuid/stats", nil)
		req.Header.Set("Authorization", "Bearer admin-token")
		req.Header.Set("X-User-Role", "admin")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte(`{"error":"invalid library id"}`))
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusBadRequest, rr.Code)
	})

	t.Run("GET /api/libraries/:id/stats - Get stats successfully", func(t *testing.T) {
		req := httptest.NewRequest("GET", "/api/libraries/"+libraryID.String()+"/stats", nil)
		req.Header.Set("Authorization", "Bearer admin-token")
		req.Header.Set("X-User-Role", "admin")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			stats := map[string]interface{}{
				"media_count": 42,
				"total_size":  1024000,
			}
			w.WriteHeader(http.StatusOK)
			json.NewEncoder(w).Encode(stats)
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusOK, rr.Code)
	})
}

// TestLibraryTypes tests library type retrieval
func TestLibraryTypes(t *testing.T) {
	t.Run("GET /api/libraries/types - Get all library types", func(t *testing.T) {
		req := httptest.NewRequest("GET", "/api/libraries/types", nil)
		req.Header.Set("Authorization", "Bearer valid-token")
		rr := httptest.NewRecorder()

		handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			types := []map[string]interface{}{
				{
					"id":                 uuid.New().String(),
					"name":               "ebooks",
					"description":        "Ebook files including EPUB, PDF, MOBI, etc.",
					"allowed_extensions": []string{".epub", ".pdf", ".mobi"},
				},
				{
					"id":                 uuid.New().String(),
					"name":               "comics",
					"description":        "Comic book archives and image formats",
					"allowed_extensions": []string{".cbz", ".cbr", ".cb7", ".cbt", ".epub", ".pdf"},
				},
			}
			w.WriteHeader(http.StatusOK)
			json.NewEncoder(w).Encode(types)
		})

		handler.ServeHTTP(rr, req)
		assert.Equal(t, http.StatusOK, rr.Code)
		assert.Contains(t, rr.Body.String(), "ebooks")
		assert.Contains(t, rr.Body.String(), "comics")
	})
}
