package matrix

import (
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"
)

// ========================================
// Test Helpers
// ========================================

// createTestServer creates a mock Matrix server for testing
func createTestServer(t *testing.T, handler http.HandlerFunc) (*httptest.Server, *MatrixService) {
	server := httptest.NewServer(handler)
	service := NewMatrixService(Config{
		HomeserverURL: server.URL,
		AccessToken:   "test-access-token",
		ServerName:    "test.local",
	})
	return server, service
}

// ========================================
// Unit Tests: Service Creation
// ========================================

func TestNewMatrixService_ValidConfig_CreatesService(t *testing.T) {
	cfg := Config{
		HomeserverURL: "http://localhost:8008",
		AccessToken:   "test-token",
		ServerName:    "breakpilot.local",
	}

	service := NewMatrixService(cfg)

	if service == nil {
		t.Fatal("Expected service to be created, got nil")
	}
	if service.homeserverURL != cfg.HomeserverURL {
		t.Errorf("Expected homeserverURL %s, got %s", cfg.HomeserverURL, service.homeserverURL)
	}
	if service.accessToken != cfg.AccessToken {
		t.Errorf("Expected accessToken %s, got %s", cfg.AccessToken, service.accessToken)
	}
	if service.serverName != cfg.ServerName {
		t.Errorf("Expected serverName %s, got %s", cfg.ServerName, service.serverName)
	}
	if service.httpClient == nil {
		t.Error("Expected httpClient to be initialized")
	}
	if service.httpClient.Timeout != 30*time.Second {
		t.Errorf("Expected timeout 30s, got %v", service.httpClient.Timeout)
	}
}

func TestGetServerName_ReturnsConfiguredName(t *testing.T) {
	service := NewMatrixService(Config{
		HomeserverURL: "http://localhost:8008",
		AccessToken:   "test-token",
		ServerName:    "school.example.com",
	})

	result := service.GetServerName()

	if result != "school.example.com" {
		t.Errorf("Expected 'school.example.com', got '%s'", result)
	}
}

func TestGenerateUserID_ValidUsername_ReturnsFormattedID(t *testing.T) {
	tests := []struct {
		name       string
		serverName string
		username   string
		expected   string
	}{
		{
			name:       "simple username",
			serverName: "breakpilot.local",
			username:   "max.mustermann",
			expected:   "@max.mustermann:breakpilot.local",
		},
		{
			name:       "teacher username",
			serverName: "school.de",
			username:   "lehrer_mueller",
			expected:   "@lehrer_mueller:school.de",
		},
		{
			name:       "parent username with numbers",
			serverName: "test.local",
			username:   "eltern123",
			expected:   "@eltern123:test.local",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			service := NewMatrixService(Config{
				HomeserverURL: "http://localhost:8008",
				AccessToken:   "test-token",
				ServerName:    tt.serverName,
			})

			result := service.GenerateUserID(tt.username)

			if result != tt.expected {
				t.Errorf("Expected '%s', got '%s'", tt.expected, result)
			}
		})
	}
}

// ========================================
// Unit Tests: Health Check
// ========================================

func TestHealthCheck_ServerHealthy_ReturnsNil(t *testing.T) {
	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/_matrix/client/versions" {
			t.Errorf("Expected path /_matrix/client/versions, got %s", r.URL.Path)
		}
		if r.Method != "GET" {
			t.Errorf("Expected GET method, got %s", r.Method)
		}
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"versions": []string{"v1.1", "v1.2"},
		})
	})
	defer server.Close()

	err := service.HealthCheck(context.Background())

	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}
}

func TestHealthCheck_ServerUnreachable_ReturnsError(t *testing.T) {
	service := NewMatrixService(Config{
		HomeserverURL: "http://localhost:59999", // Non-existent server
		AccessToken:   "test-token",
		ServerName:    "test.local",
	})

	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
	defer cancel()

	err := service.HealthCheck(ctx)

	if err == nil {
		t.Error("Expected error for unreachable server, got nil")
	}
	if !strings.Contains(err.Error(), "unreachable") {
		t.Errorf("Expected 'unreachable' in error message, got: %v", err)
	}
}

func TestHealthCheck_ServerReturns500_ReturnsError(t *testing.T) {
	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusInternalServerError)
	})
	defer server.Close()

	err := service.HealthCheck(context.Background())

	if err == nil {
		t.Error("Expected error for 500 response, got nil")
	}
	if !strings.Contains(err.Error(), "500") {
		t.Errorf("Expected '500' in error message, got: %v", err)
	}
}

// ========================================
// Unit Tests: Room Creation
// ========================================

func TestCreateRoom_ValidRequest_ReturnsRoomID(t *testing.T) {
	expectedRoomID := "!abc123:test.local"

	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/_matrix/client/v3/createRoom" {
			t.Errorf("Expected path /_matrix/client/v3/createRoom, got %s", r.URL.Path)
		}
		if r.Method != "POST" {
			t.Errorf("Expected POST method, got %s", r.Method)
		}

		// Verify authorization header
		auth := r.Header.Get("Authorization")
		if auth != "Bearer test-access-token" {
			t.Errorf("Expected 'Bearer test-access-token', got '%s'", auth)
		}

		// Verify content type
		contentType := r.Header.Get("Content-Type")
		if contentType != "application/json" {
			t.Errorf("Expected 'application/json', got '%s'", contentType)
		}

		// Decode and verify request body
		var req CreateRoomRequest
		if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
			t.Fatalf("Failed to decode request body: %v", err)
		}

		if req.Name != "Test Room" {
			t.Errorf("Expected name 'Test Room', got '%s'", req.Name)
		}

		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(CreateRoomResponse{
			RoomID: expectedRoomID,
		})
	})
	defer server.Close()

	req := CreateRoomRequest{
		Name:       "Test Room",
		Visibility: "private",
	}

	result, err := service.CreateRoom(context.Background(), req)

	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if result.RoomID != expectedRoomID {
		t.Errorf("Expected room ID '%s', got '%s'", expectedRoomID, result.RoomID)
	}
}

func TestCreateRoom_ServerError_ReturnsError(t *testing.T) {
	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusForbidden)
		json.NewEncoder(w).Encode(map[string]string{
			"errcode": "M_FORBIDDEN",
			"error":   "Not allowed to create rooms",
		})
	})
	defer server.Close()

	req := CreateRoomRequest{Name: "Test"}

	_, err := service.CreateRoom(context.Background(), req)

	if err == nil {
		t.Error("Expected error, got nil")
	}
	if !strings.Contains(err.Error(), "M_FORBIDDEN") {
		t.Errorf("Expected 'M_FORBIDDEN' in error, got: %v", err)
	}
}

func TestCreateClassInfoRoom_ValidInput_CreatesRoomWithCorrectPowerLevels(t *testing.T) {
	var receivedRequest CreateRoomRequest

	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		json.NewDecoder(r.Body).Decode(&receivedRequest)
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(CreateRoomResponse{RoomID: "!class:test.local"})
	})
	defer server.Close()

	teacherIDs := []string{"@lehrer1:test.local", "@lehrer2:test.local"}
	result, err := service.CreateClassInfoRoom(context.Background(), "5a", "Grundschule Musterstadt", teacherIDs)

	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if result.RoomID != "!class:test.local" {
		t.Errorf("Expected room ID '!class:test.local', got '%s'", result.RoomID)
	}

	// Verify room name format
	expectedName := "5a - Grundschule Musterstadt (Info)"
	if receivedRequest.Name != expectedName {
		t.Errorf("Expected name '%s', got '%s'", expectedName, receivedRequest.Name)
	}

	// Verify power levels
	if receivedRequest.PowerLevelContentOverride == nil {
		t.Fatal("Expected power level override, got nil")
	}
	if receivedRequest.PowerLevelContentOverride.EventsDefault != 50 {
		t.Errorf("Expected EventsDefault 50, got %d", receivedRequest.PowerLevelContentOverride.EventsDefault)
	}
	if receivedRequest.PowerLevelContentOverride.UsersDefault != 0 {
		t.Errorf("Expected UsersDefault 0, got %d", receivedRequest.PowerLevelContentOverride.UsersDefault)
	}

	// Verify teachers have power level 50
	for _, teacherID := range teacherIDs {
		if level, ok := receivedRequest.PowerLevelContentOverride.Users[teacherID]; !ok || level != 50 {
			t.Errorf("Expected teacher %s to have power level 50, got %d", teacherID, level)
		}
	}
}

func TestCreateStudentDMRoom_ValidInput_CreatesEncryptedRoom(t *testing.T) {
	var receivedRequest CreateRoomRequest

	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		json.NewDecoder(r.Body).Decode(&receivedRequest)
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(CreateRoomResponse{RoomID: "!dm:test.local"})
	})
	defer server.Close()

	teacherIDs := []string{"@lehrer:test.local"}
	parentIDs := []string{"@eltern1:test.local", "@eltern2:test.local"}

	result, err := service.CreateStudentDMRoom(context.Background(), "Max Mustermann", "5a", teacherIDs, parentIDs)

	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if result.RoomID != "!dm:test.local" {
		t.Errorf("Expected room ID '!dm:test.local', got '%s'", result.RoomID)
	}

	// Verify room name
	expectedName := "Max Mustermann (5a) - Dialog"
	if receivedRequest.Name != expectedName {
		t.Errorf("Expected name '%s', got '%s'", expectedName, receivedRequest.Name)
	}

	// Verify encryption is enabled
	foundEncryption := false
	for _, state := range receivedRequest.InitialState {
		if state.Type == "m.room.encryption" {
			foundEncryption = true
			// Content comes as map[string]interface{} from JSON unmarshaling
			content, ok := state.Content.(map[string]interface{})
			if !ok {
				t.Errorf("Expected encryption content to be map[string]interface{}, got %T", state.Content)
				continue
			}
			if algo, ok := content["algorithm"].(string); !ok || algo != "m.megolm.v1.aes-sha2" {
				t.Errorf("Expected algorithm 'm.megolm.v1.aes-sha2', got '%v'", content["algorithm"])
			}
		}
	}
	if !foundEncryption {
		t.Error("Expected encryption state event, not found")
	}

	// Verify all users are invited
	expectedInvites := append(teacherIDs, parentIDs...)
	for _, expected := range expectedInvites {
		found := false
		for _, invited := range receivedRequest.Invite {
			if invited == expected {
				found = true
				break
			}
		}
		if !found {
			t.Errorf("Expected user %s to be invited", expected)
		}
	}
}

func TestCreateParentRepRoom_ValidInput_CreatesRoom(t *testing.T) {
	var receivedRequest CreateRoomRequest

	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		json.NewDecoder(r.Body).Decode(&receivedRequest)
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(CreateRoomResponse{RoomID: "!rep:test.local"})
	})
	defer server.Close()

	teacherIDs := []string{"@lehrer:test.local"}
	repIDs := []string{"@elternvertreter1:test.local", "@elternvertreter2:test.local"}

	result, err := service.CreateParentRepRoom(context.Background(), "5a", teacherIDs, repIDs)

	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if result.RoomID != "!rep:test.local" {
		t.Errorf("Expected room ID '!rep:test.local', got '%s'", result.RoomID)
	}

	// Verify room name
	expectedName := "5a - Elternvertreter"
	if receivedRequest.Name != expectedName {
		t.Errorf("Expected name '%s', got '%s'", expectedName, receivedRequest.Name)
	}

	// Verify all participants can write (power level 50)
	allUsers := append(teacherIDs, repIDs...)
	for _, userID := range allUsers {
		if level, ok := receivedRequest.PowerLevelContentOverride.Users[userID]; !ok || level != 50 {
			t.Errorf("Expected user %s to have power level 50, got %d", userID, level)
		}
	}
}

// ========================================
// Unit Tests: User Management
// ========================================

func TestSetDisplayName_ValidRequest_Succeeds(t *testing.T) {
	var receivedPath string
	var receivedBody map[string]string

	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		receivedPath = r.URL.Path
		json.NewDecoder(r.Body).Decode(&receivedBody)
		w.WriteHeader(http.StatusOK)
	})
	defer server.Close()

	err := service.SetDisplayName(context.Background(), "@user:test.local", "Max Mustermann")

	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}

	// Path may or may not be URL-encoded depending on Go version
	if !strings.Contains(receivedPath, "/profile/") || !strings.Contains(receivedPath, "/displayname") {
		t.Errorf("Expected path to contain '/profile/' and '/displayname', got '%s'", receivedPath)
	}

	if receivedBody["displayname"] != "Max Mustermann" {
		t.Errorf("Expected displayname 'Max Mustermann', got '%s'", receivedBody["displayname"])
	}
}

// ========================================
// Unit Tests: Room Membership
// ========================================

func TestInviteUser_ValidRequest_Succeeds(t *testing.T) {
	var receivedBody InviteRequest

	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		if !strings.Contains(r.URL.Path, "/invite") {
			t.Errorf("Expected path to contain '/invite', got '%s'", r.URL.Path)
		}
		if r.Method != "POST" {
			t.Errorf("Expected POST method, got %s", r.Method)
		}
		json.NewDecoder(r.Body).Decode(&receivedBody)
		w.WriteHeader(http.StatusOK)
	})
	defer server.Close()

	err := service.InviteUser(context.Background(), "!room:test.local", "@user:test.local")

	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if receivedBody.UserID != "@user:test.local" {
		t.Errorf("Expected user_id '@user:test.local', got '%s'", receivedBody.UserID)
	}
}

func TestInviteUser_UserAlreadyInRoom_ReturnsError(t *testing.T) {
	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusForbidden)
		json.NewEncoder(w).Encode(map[string]string{
			"errcode": "M_FORBIDDEN",
			"error":   "User is already in the room",
		})
	})
	defer server.Close()

	err := service.InviteUser(context.Background(), "!room:test.local", "@user:test.local")

	if err == nil {
		t.Error("Expected error, got nil")
	}
}

func TestJoinRoom_ValidRequest_Succeeds(t *testing.T) {
	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		if !strings.Contains(r.URL.Path, "/join/") {
			t.Errorf("Expected path to contain '/join/', got '%s'", r.URL.Path)
		}
		if r.Method != "POST" {
			t.Errorf("Expected POST method, got %s", r.Method)
		}
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(map[string]string{"room_id": "!room:test.local"})
	})
	defer server.Close()

	err := service.JoinRoom(context.Background(), "!room:test.local")

	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
}

// ========================================
// Unit Tests: Messaging
// ========================================

func TestSendMessage_ValidRequest_Succeeds(t *testing.T) {
	var receivedBody SendMessageRequest

	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		if !strings.Contains(r.URL.Path, "/send/m.room.message/") {
			t.Errorf("Expected path to contain '/send/m.room.message/', got '%s'", r.URL.Path)
		}
		if r.Method != "PUT" {
			t.Errorf("Expected PUT method, got %s", r.Method)
		}
		json.NewDecoder(r.Body).Decode(&receivedBody)
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(map[string]string{"event_id": "$event123"})
	})
	defer server.Close()

	err := service.SendMessage(context.Background(), "!room:test.local", "Hello, World!")

	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if receivedBody.MsgType != "m.text" {
		t.Errorf("Expected msgtype 'm.text', got '%s'", receivedBody.MsgType)
	}
	if receivedBody.Body != "Hello, World!" {
		t.Errorf("Expected body 'Hello, World!', got '%s'", receivedBody.Body)
	}
}

func TestSendHTMLMessage_ValidRequest_IncludesFormattedBody(t *testing.T) {
	var receivedBody SendMessageRequest

	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		json.NewDecoder(r.Body).Decode(&receivedBody)
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(map[string]string{"event_id": "$event123"})
	})
	defer server.Close()

	err := service.SendHTMLMessage(context.Background(), "!room:test.local", "Plain text", "<b>Bold text</b>")

	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if receivedBody.Format != "org.matrix.custom.html" {
		t.Errorf("Expected format 'org.matrix.custom.html', got '%s'", receivedBody.Format)
	}
	if receivedBody.Body != "Plain text" {
		t.Errorf("Expected body 'Plain text', got '%s'", receivedBody.Body)
	}
	if receivedBody.FormattedBody != "<b>Bold text</b>" {
		t.Errorf("Expected formatted_body '<b>Bold text</b>', got '%s'", receivedBody.FormattedBody)
	}
}

func TestSendAbsenceNotification_ValidRequest_FormatsCorrectly(t *testing.T) {
	var receivedBody SendMessageRequest

	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		json.NewDecoder(r.Body).Decode(&receivedBody)
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(map[string]string{"event_id": "$event123"})
	})
	defer server.Close()

	err := service.SendAbsenceNotification(context.Background(), "!room:test.local", "Max Mustermann", "15.12.2025", 3)

	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}

	// Verify plain text contains key information
	if !strings.Contains(receivedBody.Body, "Max Mustermann") {
		t.Error("Expected body to contain student name")
	}
	if !strings.Contains(receivedBody.Body, "15.12.2025") {
		t.Error("Expected body to contain date")
	}
	if !strings.Contains(receivedBody.Body, "3. Stunde") {
		t.Error("Expected body to contain lesson number")
	}
	if !strings.Contains(receivedBody.Body, "Abwesenheitsmeldung") {
		t.Error("Expected body to contain 'Abwesenheitsmeldung'")
	}

	// Verify HTML is set
	if receivedBody.FormattedBody == "" {
		t.Error("Expected formatted body to be set")
	}
}

func TestSendGradeNotification_ValidRequest_FormatsCorrectly(t *testing.T) {
	var receivedBody SendMessageRequest

	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		json.NewDecoder(r.Body).Decode(&receivedBody)
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(map[string]string{"event_id": "$event123"})
	})
	defer server.Close()

	err := service.SendGradeNotification(context.Background(), "!room:test.local", "Max Mustermann", "Mathematik", "Klassenarbeit", 2.3)

	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}

	if !strings.Contains(receivedBody.Body, "Max Mustermann") {
		t.Error("Expected body to contain student name")
	}
	if !strings.Contains(receivedBody.Body, "Mathematik") {
		t.Error("Expected body to contain subject")
	}
	if !strings.Contains(receivedBody.Body, "Klassenarbeit") {
		t.Error("Expected body to contain grade type")
	}
	if !strings.Contains(receivedBody.Body, "2.3") {
		t.Error("Expected body to contain grade")
	}
}

func TestSendClassAnnouncement_ValidRequest_FormatsCorrectly(t *testing.T) {
	var receivedBody SendMessageRequest

	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		json.NewDecoder(r.Body).Decode(&receivedBody)
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(map[string]string{"event_id": "$event123"})
	})
	defer server.Close()

	err := service.SendClassAnnouncement(context.Background(), "!room:test.local", "Elternabend", "Am 20.12. findet der Elternabend statt.", "Frau Müller")

	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}

	if !strings.Contains(receivedBody.Body, "Elternabend") {
		t.Error("Expected body to contain title")
	}
	if !strings.Contains(receivedBody.Body, "20.12.") {
		t.Error("Expected body to contain content")
	}
	if !strings.Contains(receivedBody.Body, "Frau Müller") {
		t.Error("Expected body to contain teacher name")
	}
}

// ========================================
// Unit Tests: Power Levels
// ========================================

func TestSetUserPowerLevel_ValidRequest_UpdatesPowerLevel(t *testing.T) {
	callCount := 0
	var putBody PowerLevels

	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		callCount++
		if r.Method == "GET" {
			// Return current power levels
			w.WriteHeader(http.StatusOK)
			json.NewEncoder(w).Encode(PowerLevels{
				Users: map[string]int{
					"@admin:test.local": 100,
				},
				UsersDefault: 0,
			})
		} else if r.Method == "PUT" {
			// Update power levels
			json.NewDecoder(r.Body).Decode(&putBody)
			w.WriteHeader(http.StatusOK)
		}
	})
	defer server.Close()

	err := service.SetUserPowerLevel(context.Background(), "!room:test.local", "@newuser:test.local", 50)

	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if callCount != 2 {
		t.Errorf("Expected 2 API calls (GET then PUT), got %d", callCount)
	}
	if putBody.Users["@newuser:test.local"] != 50 {
		t.Errorf("Expected user power level 50, got %d", putBody.Users["@newuser:test.local"])
	}
	// Verify existing users are preserved
	if putBody.Users["@admin:test.local"] != 100 {
		t.Errorf("Expected admin power level 100 to be preserved, got %d", putBody.Users["@admin:test.local"])
	}
}

// ========================================
// Unit Tests: Error Handling
// ========================================

func TestParseError_MatrixError_ExtractsFields(t *testing.T) {
	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(map[string]string{
			"errcode": "M_UNKNOWN",
			"error":   "Something went wrong",
		})
	})
	defer server.Close()

	_, err := service.CreateRoom(context.Background(), CreateRoomRequest{Name: "Test"})

	if err == nil {
		t.Fatal("Expected error, got nil")
	}
	if !strings.Contains(err.Error(), "M_UNKNOWN") {
		t.Errorf("Expected error to contain 'M_UNKNOWN', got: %v", err)
	}
	if !strings.Contains(err.Error(), "Something went wrong") {
		t.Errorf("Expected error to contain 'Something went wrong', got: %v", err)
	}
}

func TestParseError_NonJSONError_ReturnsRawBody(t *testing.T) {
	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("Internal Server Error"))
	})
	defer server.Close()

	_, err := service.CreateRoom(context.Background(), CreateRoomRequest{Name: "Test"})

	if err == nil {
		t.Fatal("Expected error, got nil")
	}
	if !strings.Contains(err.Error(), "500") {
		t.Errorf("Expected error to contain '500', got: %v", err)
	}
}

// ========================================
// Unit Tests: Context Handling
// ========================================

func TestCreateRoom_ContextCanceled_ReturnsError(t *testing.T) {
	server, service := createTestServer(t, func(w http.ResponseWriter, r *http.Request) {
		time.Sleep(100 * time.Millisecond)
		w.WriteHeader(http.StatusOK)
	})
	defer server.Close()

	ctx, cancel := context.WithCancel(context.Background())
	cancel() // Cancel immediately

	_, err := service.CreateRoom(ctx, CreateRoomRequest{Name: "Test"})

	if err == nil {
		t.Error("Expected error for canceled context, got nil")
	}
}

// ========================================
// Integration Tests (require running Synapse)
// ========================================

// These tests are skipped by default as they require a running Matrix server
// Run with: go test -tags=integration ./...

func TestIntegration_HealthCheck(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test in short mode")
	}

	service := NewMatrixService(Config{
		HomeserverURL: "http://localhost:8008",
		AccessToken:   "", // Not needed for health check
		ServerName:    "breakpilot.local",
	})

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	err := service.HealthCheck(ctx)
	if err != nil {
		t.Skipf("Matrix server not available: %v", err)
	}
}
