package blossom

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"git.mleku.dev/mleku/nostr/encoders/event"
	"git.mleku.dev/mleku/nostr/encoders/hex"
	"git.mleku.dev/mleku/nostr/encoders/tag"
	"git.mleku.dev/mleku/nostr/encoders/timestamp"
)

// TestFullServerIntegration tests a complete workflow with a real HTTP server
func TestFullServerIntegration(t *testing.T) {
	server, cleanup := testSetup(t)
	defer cleanup()

	// Start real HTTP server
	httpServer := httptest.NewServer(server.Handler())
	defer httpServer.Close()

	baseURL := httpServer.URL
	client := &http.Client{Timeout: 10 * time.Second}

	// Create test keypair
	_, signer := createTestKeypair(t)
	pubkey := signer.Pub()
	pubkeyHex := hex.Enc(pubkey)

	// Step 1: Upload a blob
	testData := []byte("integration test blob content")
	sha256Hash := CalculateSHA256(testData)
	sha256Hex := hex.Enc(sha256Hash)

	authEv := createAuthEvent(t, signer, "upload", sha256Hash, 3600)

	uploadReq, err := http.NewRequest("PUT", baseURL+"/upload", bytes.NewReader(testData))
	if err != nil {
		t.Fatalf("Failed to create upload request: %v", err)
	}
	uploadReq.Header.Set("Authorization", createAuthHeader(authEv))
	uploadReq.Header.Set("Content-Type", "text/plain")

	uploadResp, err := client.Do(uploadReq)
	if err != nil {
		t.Fatalf("Failed to upload: %v", err)
	}
	defer uploadResp.Body.Close()

	if uploadResp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(uploadResp.Body)
		t.Fatalf("Upload failed: status %d, body: %s", uploadResp.StatusCode, string(body))
	}

	var uploadDesc BlobDescriptor
	if err := json.NewDecoder(uploadResp.Body).Decode(&uploadDesc); err != nil {
		t.Fatalf("Failed to parse upload response: %v", err)
	}

	if uploadDesc.SHA256 != sha256Hex {
		t.Errorf("SHA256 mismatch: expected %s, got %s", sha256Hex, uploadDesc.SHA256)
	}

	// Step 2: Retrieve the blob
	getReq, err := http.NewRequest("GET", baseURL+"/"+sha256Hex, nil)
	if err != nil {
		t.Fatalf("Failed to create GET request: %v", err)
	}

	getResp, err := client.Do(getReq)
	if err != nil {
		t.Fatalf("Failed to get blob: %v", err)
	}
	defer getResp.Body.Close()

	if getResp.StatusCode != http.StatusOK {
		t.Fatalf("Get failed: status %d", getResp.StatusCode)
	}

	retrievedData, err := io.ReadAll(getResp.Body)
	if err != nil {
		t.Fatalf("Failed to read response: %v", err)
	}

	if !bytes.Equal(retrievedData, testData) {
		t.Error("Retrieved blob data mismatch")
	}

	// Step 3: List blobs
	listAuthEv := createAuthEvent(t, signer, "list", nil, 3600)
	listReq, err := http.NewRequest("GET", baseURL+"/list/"+pubkeyHex, nil)
	if err != nil {
		t.Fatalf("Failed to create list request: %v", err)
	}
	listReq.Header.Set("Authorization", createAuthHeader(listAuthEv))

	listResp, err := client.Do(listReq)
	if err != nil {
		t.Fatalf("Failed to list blobs: %v", err)
	}
	defer listResp.Body.Close()

	if listResp.StatusCode != http.StatusOK {
		t.Fatalf("List failed: status %d", listResp.StatusCode)
	}

	var descriptors []BlobDescriptor
	if err := json.NewDecoder(listResp.Body).Decode(&descriptors); err != nil {
		t.Fatalf("Failed to parse list response: %v", err)
	}

	if len(descriptors) == 0 {
		t.Error("Expected at least one blob in list")
	}

	// Step 4: Delete the blob
	deleteAuthEv := createAuthEvent(t, signer, "delete", sha256Hash, 3600)
	deleteReq, err := http.NewRequest("DELETE", baseURL+"/"+sha256Hex, nil)
	if err != nil {
		t.Fatalf("Failed to create delete request: %v", err)
	}
	deleteReq.Header.Set("Authorization", createAuthHeader(deleteAuthEv))

	deleteResp, err := client.Do(deleteReq)
	if err != nil {
		t.Fatalf("Failed to delete blob: %v", err)
	}
	defer deleteResp.Body.Close()

	if deleteResp.StatusCode != http.StatusOK {
		t.Fatalf("Delete failed: status %d", deleteResp.StatusCode)
	}

	// Step 5: Verify blob is gone
	getResp2, err := client.Do(getReq)
	if err != nil {
		t.Fatalf("Failed to get blob: %v", err)
	}
	defer getResp2.Body.Close()

	if getResp2.StatusCode != http.StatusNotFound {
		t.Errorf("Expected 404 after delete, got %d", getResp2.StatusCode)
	}
}

// TestServerWithMultipleBlobs tests multiple blob operations
func TestServerWithMultipleBlobs(t *testing.T) {
	server, cleanup := testSetup(t)
	defer cleanup()

	httpServer := httptest.NewServer(server.Handler())
	defer httpServer.Close()

	_, signer := createTestKeypair(t)
	pubkey := signer.Pub()
	pubkeyHex := hex.Enc(pubkey)

	// Upload multiple blobs
	const numBlobs = 5
	var hashes []string
	var data []byte

	for i := 0; i < numBlobs; i++ {
		testData := []byte(fmt.Sprintf("blob %d content", i))
		sha256Hash := CalculateSHA256(testData)
		sha256Hex := hex.Enc(sha256Hash)
		hashes = append(hashes, sha256Hex)
		data = append(data, testData...)

		authEv := createAuthEvent(t, signer, "upload", sha256Hash, 3600)

		req, _ := http.NewRequest("PUT", httpServer.URL+"/upload", bytes.NewReader(testData))
		req.Header.Set("Authorization", createAuthHeader(authEv))

		resp, err := http.DefaultClient.Do(req)
		if err != nil {
			t.Fatalf("Failed to upload blob %d: %v", i, err)
		}
		resp.Body.Close()

		if resp.StatusCode != http.StatusOK {
			t.Errorf("Upload %d failed: status %d", i, resp.StatusCode)
		}
	}

	// List all blobs
	authEv := createAuthEvent(t, signer, "list", nil, 3600)
	req, _ := http.NewRequest("GET", httpServer.URL+"/list/"+pubkeyHex, nil)
	req.Header.Set("Authorization", createAuthHeader(authEv))

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		t.Fatalf("Failed to list blobs: %v", err)
	}
	defer resp.Body.Close()

	var descriptors []BlobDescriptor
	json.NewDecoder(resp.Body).Decode(&descriptors)

	if len(descriptors) != numBlobs {
		t.Errorf("Expected %d blobs, got %d", numBlobs, len(descriptors))
	}
}

// TestServerCORS tests CORS headers on all endpoints
func TestServerCORS(t *testing.T) {
	server, cleanup := testSetup(t)
	defer cleanup()

	httpServer := httptest.NewServer(server.Handler())
	defer httpServer.Close()

	endpoints := []struct {
		method string
		path   string
	}{
		{"GET", "/test123456789012345678901234567890123456789012345678901234567890"},
		{"HEAD", "/test123456789012345678901234567890123456789012345678901234567890"},
		{"PUT", "/upload"},
		{"HEAD", "/upload"},
		{"GET", "/list/test123456789012345678901234567890123456789012345678901234567890"},
		{"PUT", "/media"},
		{"HEAD", "/media"},
		{"PUT", "/mirror"},
		{"PUT", "/report"},
		{"DELETE", "/test123456789012345678901234567890123456789012345678901234567890"},
		{"OPTIONS", "/"},
	}

	for _, ep := range endpoints {
		req, _ := http.NewRequest(ep.method, httpServer.URL+ep.path, nil)
		resp, err := http.DefaultClient.Do(req)
		if err != nil {
			t.Errorf("Failed to test %s %s: %v", ep.method, ep.path, err)
			continue
		}
		resp.Body.Close()

		corsHeader := resp.Header.Get("Access-Control-Allow-Origin")
		if corsHeader != "*" {
			t.Errorf("Missing CORS header on %s %s", ep.method, ep.path)
		}
	}
}

// TestServerRangeRequests tests range request handling
func TestServerRangeRequests(t *testing.T) {
	server, cleanup := testSetup(t)
	defer cleanup()

	httpServer := httptest.NewServer(server.Handler())
	defer httpServer.Close()

	// Upload a blob
	testData := []byte("0123456789abcdefghij")
	sha256Hash := CalculateSHA256(testData)
	pubkey := []byte("testpubkey123456789012345678901234")

	err := server.storage.SaveBlob(sha256Hash, testData, pubkey, "text/plain", "")
	if err != nil {
		t.Fatalf("Failed to save blob: %v", err)
	}

	sha256Hex := hex.Enc(sha256Hash)

	// Test various range requests
	tests := []struct {
		rangeHeader string
		expected    string
		status      int
	}{
		{"bytes=0-4", "01234", http.StatusPartialContent},
		{"bytes=5-9", "56789", http.StatusPartialContent},
		{"bytes=10-", "abcdefghij", http.StatusPartialContent},
		{"bytes=-5", "fghij", http.StatusPartialContent},
		{"bytes=0-0", "0", http.StatusPartialContent},
		{"bytes=100-200", "", http.StatusRequestedRangeNotSatisfiable},
	}

	for _, tt := range tests {
		req, _ := http.NewRequest("GET", httpServer.URL+"/"+sha256Hex, nil)
		req.Header.Set("Range", tt.rangeHeader)

		resp, err := http.DefaultClient.Do(req)
		if err != nil {
			t.Errorf("Failed to request range %s: %v", tt.rangeHeader, err)
			continue
		}

		if resp.StatusCode != tt.status {
			t.Errorf("Range %s: expected status %d, got %d", tt.rangeHeader, tt.status, resp.StatusCode)
			resp.Body.Close()
			continue
		}

		if tt.status == http.StatusPartialContent {
			body, _ := io.ReadAll(resp.Body)
			if string(body) != tt.expected {
				t.Errorf("Range %s: expected %q, got %q", tt.rangeHeader, tt.expected, string(body))
			}

			if resp.Header.Get("Content-Range") == "" {
				t.Errorf("Range %s: missing Content-Range header", tt.rangeHeader)
			}
		}

		resp.Body.Close()
	}
}

// TestServerAuthorizationFlow tests complete authorization flow
func TestServerAuthorizationFlow(t *testing.T) {
	server, cleanup := testSetup(t)
	defer cleanup()

	_, signer := createTestKeypair(t)

	testData := []byte("authorized blob")
	sha256Hash := CalculateSHA256(testData)

	// Test with valid authorization
	authEv := createAuthEvent(t, signer, "upload", sha256Hash, 3600)

	req := httptest.NewRequest("PUT", "/upload", bytes.NewReader(testData))
	req.Header.Set("Authorization", createAuthHeader(authEv))

	w := httptest.NewRecorder()
	server.Handler().ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("Valid auth failed: status %d, body: %s", w.Code, w.Body.String())
	}

	// Test with expired authorization
	expiredAuthEv := createAuthEvent(t, signer, "upload", sha256Hash, -3600)

	req2 := httptest.NewRequest("PUT", "/upload", bytes.NewReader(testData))
	req2.Header.Set("Authorization", createAuthHeader(expiredAuthEv))

	w2 := httptest.NewRecorder()
	server.Handler().ServeHTTP(w2, req2)

	if w2.Code != http.StatusUnauthorized {
		t.Errorf("Expired auth should fail: status %d", w2.Code)
	}

	// Test with wrong verb
	wrongVerbAuthEv := createAuthEvent(t, signer, "delete", sha256Hash, 3600)

	req3 := httptest.NewRequest("PUT", "/upload", bytes.NewReader(testData))
	req3.Header.Set("Authorization", createAuthHeader(wrongVerbAuthEv))

	w3 := httptest.NewRecorder()
	server.Handler().ServeHTTP(w3, req3)

	if w3.Code != http.StatusUnauthorized {
		t.Errorf("Wrong verb auth should fail: status %d", w3.Code)
	}
}

// TestServerUploadRequirementsFlow tests upload requirements check flow
func TestServerUploadRequirementsFlow(t *testing.T) {
	server, cleanup := testSetup(t)
	defer cleanup()

	testData := []byte("test")
	sha256Hash := CalculateSHA256(testData)

	// Test HEAD /upload with valid requirements
	req := httptest.NewRequest("HEAD", "/upload", nil)
	req.Header.Set("X-SHA-256", hex.Enc(sha256Hash))
	req.Header.Set("X-Content-Length", "4")
	req.Header.Set("X-Content-Type", "text/plain")

	w := httptest.NewRecorder()
	server.Handler().ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("Upload requirements check failed: status %d", w.Code)
	}

	// Test HEAD /upload with missing header
	req2 := httptest.NewRequest("HEAD", "/upload", nil)
	w2 := httptest.NewRecorder()
	server.Handler().ServeHTTP(w2, req2)

	if w2.Code != http.StatusBadRequest {
		t.Errorf("Expected BadRequest for missing header, got %d", w2.Code)
	}

	// Test HEAD /upload with invalid hash
	req3 := httptest.NewRequest("HEAD", "/upload", nil)
	req3.Header.Set("X-SHA-256", "invalid")
	req3.Header.Set("X-Content-Length", "4")

	w3 := httptest.NewRecorder()
	server.Handler().ServeHTTP(w3, req3)

	if w3.Code != http.StatusBadRequest {
		t.Errorf("Expected BadRequest for invalid hash, got %d", w3.Code)
	}
}

// TestServerMirrorFlow tests mirror endpoint flow
func TestServerMirrorFlow(t *testing.T) {
	server, cleanup := testSetup(t)
	defer cleanup()

	_, signer := createTestKeypair(t)

	// Create mock remote server
	remoteData := []byte("remote blob data")
	sha256Hash := CalculateSHA256(remoteData)
	sha256Hex := hex.Enc(sha256Hash)

	mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/pdf")
		w.Header().Set("Content-Length", fmt.Sprintf("%d", len(remoteData)))
		w.Write(remoteData)
	}))
	defer mockServer.Close()

	// Mirror the blob
	mirrorReq := map[string]string{
		"url": mockServer.URL + "/" + sha256Hex,
	}
	reqBody, _ := json.Marshal(mirrorReq)

	authEv := createAuthEvent(t, signer, "upload", sha256Hash, 3600)

	req := httptest.NewRequest("PUT", "/mirror", bytes.NewReader(reqBody))
	req.Header.Set("Authorization", createAuthHeader(authEv))
	req.Header.Set("Content-Type", "application/json")

	w := httptest.NewRecorder()
	server.Handler().ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("Mirror failed: status %d, body: %s", w.Code, w.Body.String())
	}

	// Verify blob was stored
	exists, err := server.storage.HasBlob(sha256Hash)
	if err != nil {
		t.Fatalf("Failed to check blob: %v", err)
	}
	if !exists {
		t.Error("Blob should exist after mirror")
	}
}

// TestServerReportFlow tests report endpoint flow
func TestServerReportFlow(t *testing.T) {
	server, cleanup := testSetup(t)
	defer cleanup()

	_, signer := createTestKeypair(t)
	pubkey := signer.Pub()

	// Upload a blob first
	testData := []byte("reportable blob")
	sha256Hash := CalculateSHA256(testData)

	err := server.storage.SaveBlob(sha256Hash, testData, pubkey, "text/plain", "")
	if err != nil {
		t.Fatalf("Failed to save blob: %v", err)
	}

	// Create report event
	reportEv := &event.E{
		CreatedAt: timestamp.Now().V,
		Kind:      1984,
		Tags:      tag.NewS(tag.NewFromAny("x", hex.Enc(sha256Hash))),
		Content:   []byte("This blob should be reported"),
		Pubkey:    pubkey,
	}

	if err := reportEv.Sign(signer); err != nil {
		t.Fatalf("Failed to sign report: %v", err)
	}

	reqBody := reportEv.Serialize()
	req := httptest.NewRequest("PUT", "/report", bytes.NewReader(reqBody))
	req.Header.Set("Content-Type", "application/json")

	w := httptest.NewRecorder()
	server.Handler().ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("Report failed: status %d, body: %s", w.Code, w.Body.String())
	}
}

// TestServerErrorHandling tests various error scenarios
func TestServerErrorHandling(t *testing.T) {
	server, cleanup := testSetup(t)
	defer cleanup()

	tests := []struct {
		name       string
		method     string
		path       string
		headers    map[string]string
		body       []byte
		statusCode int
	}{
		{
			name:       "Invalid path",
			method:     "GET",
			path:       "/invalid",
			statusCode: http.StatusBadRequest,
		},
		{
			name:       "Non-existent blob",
			method:     "GET",
			path:       "/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
			statusCode: http.StatusNotFound,
		},
		{
			name:       "Anonymous upload allowed",
			method:     "PUT",
			path:       "/upload",
			body:       []byte("test"),
			statusCode: http.StatusOK, // RequireAuth=false and ACL=none allows anonymous uploads
		},
		{
			name:       "Invalid JSON in mirror",
			method:     "PUT",
			path:       "/mirror",
			body:       []byte("invalid json"),
			statusCode: http.StatusBadRequest,
		},
		{
			name:       "Invalid JSON in report",
			method:     "PUT",
			path:       "/report",
			body:       []byte("invalid json"),
			statusCode: http.StatusBadRequest,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			var body io.Reader
			if tt.body != nil {
				body = bytes.NewReader(tt.body)
			}

			req := httptest.NewRequest(tt.method, tt.path, body)
			for k, v := range tt.headers {
				req.Header.Set(k, v)
			}

			w := httptest.NewRecorder()
			server.Handler().ServeHTTP(w, req)

			if w.Code != tt.statusCode {
				t.Errorf("Expected status %d, got %d: %s", tt.statusCode, w.Code, w.Body.String())
			}
		})
	}
}

// TestServerMediaOptimization tests media optimization endpoint
func TestServerMediaOptimization(t *testing.T) {
	server, cleanup := testSetup(t)
	defer cleanup()

	_, signer := createTestKeypair(t)

	testData := []byte("test media for optimization")
	sha256Hash := CalculateSHA256(testData)

	authEv := createAuthEvent(t, signer, "media", sha256Hash, 3600)

	req := httptest.NewRequest("PUT", "/media", bytes.NewReader(testData))
	req.Header.Set("Authorization", createAuthHeader(authEv))
	req.Header.Set("Content-Type", "image/png")

	w := httptest.NewRecorder()
	server.Handler().ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("Media upload failed: status %d, body: %s", w.Code, w.Body.String())
	}

	var desc BlobDescriptor
	if err := json.Unmarshal(w.Body.Bytes(), &desc); err != nil {
		t.Fatalf("Failed to parse response: %v", err)
	}

	if desc.SHA256 == "" {
		t.Error("Expected SHA256 in response")
	}

	// Test HEAD /media
	req2 := httptest.NewRequest("HEAD", "/media", nil)
	w2 := httptest.NewRecorder()
	server.Handler().ServeHTTP(w2, req2)

	if w2.Code != http.StatusOK {
		t.Errorf("HEAD /media failed: status %d", w2.Code)
	}
}

// TestServerListWithQueryParams tests list endpoint with query parameters
func TestServerListWithQueryParams(t *testing.T) {
	server, cleanup := testSetup(t)
	defer cleanup()

	_, signer := createTestKeypair(t)
	pubkey := signer.Pub()
	pubkeyHex := hex.Enc(pubkey)

	// Upload blobs at different times
	now := time.Now().Unix()
	blobs := []struct {
		data      []byte
		timestamp int64
	}{
		{[]byte("blob 1"), now - 1000},
		{[]byte("blob 2"), now - 500},
		{[]byte("blob 3"), now},
	}

	for _, b := range blobs {
		sha256Hash := CalculateSHA256(b.data)
		// Manually set uploaded timestamp
		err := server.storage.SaveBlob(sha256Hash, b.data, pubkey, "text/plain", "")
		if err != nil {
			t.Fatalf("Failed to save blob: %v", err)
		}
	}

	// List with since parameter (future timestamp - should return no blobs)
	authEv := createAuthEvent(t, signer, "list", nil, 3600)
	futureTime := time.Now().Unix() + 3600 // 1 hour in the future
	req := httptest.NewRequest("GET", "/list/"+pubkeyHex+"?since="+fmt.Sprintf("%d", futureTime), nil)
	req.Header.Set("Authorization", createAuthHeader(authEv))

	w := httptest.NewRecorder()
	server.Handler().ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("List failed: status %d", w.Code)
	}

	var descriptors []BlobDescriptor
	if err := json.NewDecoder(w.Body).Decode(&descriptors); err != nil {
		t.Fatalf("Failed to parse response: %v", err)
	}

	// Should get no blobs since they were all uploaded before the future timestamp
	if len(descriptors) != 0 {
		t.Errorf("Expected 0 blobs, got %d", len(descriptors))
	}

	// Test without since parameter - should get all blobs
	req2 := httptest.NewRequest("GET", "/list/"+pubkeyHex, nil)
	req2.Header.Set("Authorization", createAuthHeader(authEv))

	w2 := httptest.NewRecorder()
	server.Handler().ServeHTTP(w2, req2)

	if w2.Code != http.StatusOK {
		t.Errorf("List failed: status %d", w2.Code)
	}

	var allDescriptors []BlobDescriptor
	if err := json.NewDecoder(w2.Body).Decode(&allDescriptors); err != nil {
		t.Fatalf("Failed to parse response: %v", err)
	}

	// Should get all 3 blobs when no filter is applied
	if len(allDescriptors) != 3 {
		t.Errorf("Expected 3 blobs, got %d", len(allDescriptors))
	}
}

// TestServerConcurrentOperations tests concurrent operations on server
func TestServerConcurrentOperations(t *testing.T) {
	server, cleanup := testSetup(t)
	defer cleanup()

	httpServer := httptest.NewServer(server.Handler())
	defer httpServer.Close()

	_, signer := createTestKeypair(t)

	const numOps = 20
	done := make(chan error, numOps)

	for i := 0; i < numOps; i++ {
		go func(id int) {
			testData := []byte(fmt.Sprintf("concurrent op %d", id))
			sha256Hash := CalculateSHA256(testData)
			sha256Hex := hex.Enc(sha256Hash)

			// Upload
			authEv := createAuthEvent(t, signer, "upload", sha256Hash, 3600)
			req, _ := http.NewRequest("PUT", httpServer.URL+"/upload", bytes.NewReader(testData))
			req.Header.Set("Authorization", createAuthHeader(authEv))

			resp, err := http.DefaultClient.Do(req)
			if err != nil {
				done <- err
				return
			}
			resp.Body.Close()

			if resp.StatusCode != http.StatusOK {
				done <- fmt.Errorf("upload failed: %d", resp.StatusCode)
				return
			}

			// Get
			req2, _ := http.NewRequest("GET", httpServer.URL+"/"+sha256Hex, nil)
			resp2, err := http.DefaultClient.Do(req2)
			if err != nil {
				done <- err
				return
			}
			resp2.Body.Close()

			if resp2.StatusCode != http.StatusOK {
				done <- fmt.Errorf("get failed: %d", resp2.StatusCode)
				return
			}

			done <- nil
		}(i)
	}

	for i := 0; i < numOps; i++ {
		if err := <-done; err != nil {
			t.Errorf("Concurrent operation failed: %v", err)
		}
	}
}

// TestServerBlobExtensionHandling tests blob retrieval with file extensions
func TestServerBlobExtensionHandling(t *testing.T) {
	server, cleanup := testSetup(t)
	defer cleanup()

	testData := []byte("test PDF content")
	sha256Hash := CalculateSHA256(testData)
	pubkey := []byte("testpubkey123456789012345678901234")

	err := server.storage.SaveBlob(sha256Hash, testData, pubkey, "application/pdf", "")
	if err != nil {
		t.Fatalf("Failed to save blob: %v", err)
	}

	sha256Hex := hex.Enc(sha256Hash)

	// Test GET with extension
	req := httptest.NewRequest("GET", "/"+sha256Hex+".pdf", nil)
	w := httptest.NewRecorder()
	server.Handler().ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("GET with extension failed: status %d", w.Code)
	}

	// Should still return correct MIME type
	if w.Header().Get("Content-Type") != "application/pdf" {
		t.Errorf("Expected application/pdf, got %s", w.Header().Get("Content-Type"))
	}
}

// TestServerBlobAlreadyExists tests uploading existing blob
func TestServerBlobAlreadyExists(t *testing.T) {
	server, cleanup := testSetup(t)
	defer cleanup()

	_, signer := createTestKeypair(t)
	pubkey := signer.Pub()

	testData := []byte("existing blob")
	sha256Hash := CalculateSHA256(testData)

	// Upload blob first time
	err := server.storage.SaveBlob(sha256Hash, testData, pubkey, "text/plain", "")
	if err != nil {
		t.Fatalf("Failed to save blob: %v", err)
	}

	// Try to upload same blob again
	authEv := createAuthEvent(t, signer, "upload", sha256Hash, 3600)

	req := httptest.NewRequest("PUT", "/upload", bytes.NewReader(testData))
	req.Header.Set("Authorization", createAuthHeader(authEv))

	w := httptest.NewRecorder()
	server.Handler().ServeHTTP(w, req)

	// Should succeed and return existing blob descriptor
	if w.Code != http.StatusOK {
		t.Errorf("Re-upload should succeed: status %d", w.Code)
	}
}

// TestServerInvalidAuthorization tests various invalid authorization scenarios
func TestServerInvalidAuthorization(t *testing.T) {
	server, cleanup := testSetup(t)
	defer cleanup()

	_, signer := createTestKeypair(t)

	testData := []byte("test")
	sha256Hash := CalculateSHA256(testData)

	tests := []struct {
		name      string
		modifyEv  func(*event.E)
		expectErr bool
	}{
		{
			name: "Missing expiration",
			modifyEv: func(ev *event.E) {
				ev.Tags = tag.NewS(tag.NewFromAny("t", "upload"))
			},
			expectErr: true,
		},
		{
			name: "Wrong kind",
			modifyEv: func(ev *event.E) {
				ev.Kind = 1
			},
			expectErr: true,
		},
		{
			name: "Wrong verb",
			modifyEv: func(ev *event.E) {
				ev.Tags = tag.NewS(
					tag.NewFromAny("t", "delete"),
					tag.NewFromAny("expiration", timestamp.FromUnix(time.Now().Unix()+3600).String()),
				)
			},
			expectErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ev := createAuthEvent(t, signer, "upload", sha256Hash, 3600)
			tt.modifyEv(ev)

			req := httptest.NewRequest("PUT", "/upload", bytes.NewReader(testData))
			req.Header.Set("Authorization", createAuthHeader(ev))

			w := httptest.NewRecorder()
			server.Handler().ServeHTTP(w, req)

			if tt.expectErr {
				if w.Code == http.StatusOK {
					t.Error("Expected error but got success")
				}
			} else {
				if w.Code != http.StatusOK {
					t.Errorf("Expected success but got error: status %d", w.Code)
				}
			}
		})
	}
}

