package api

import (
	"archive/zip"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	
	"os"
	"testing"
	"time"

	"github.com/google/uuid"
	"github.com/mish/dealspace/lib"
)

// createTestProjectWithAccess creates a project and grants the user IB admin access
func createTestProjectWithAccess(t *testing.T, db *lib.DB, cfg *lib.Config, userID string) string {
	t.Helper()

	projectID := uuid.New().String()
	now := time.Now().UnixMilli()

	// Create project entry
	key, _ := lib.DeriveProjectKey(cfg.MasterKey, projectID)
	summary, _ := lib.Pack(key, "Test Import Project")
	data, _ := lib.Pack(key, `{"name": "Test Import Project"}`)

	db.Conn.Exec(
		`INSERT INTO entries (entry_id, project_id, parent_id, type, depth,
		  search_key, search_key2, summary, data, stage,
		  assignee_id, return_to_id, origin_id,
		  version, deleted_at, deleted_by, key_version,
		  created_at, updated_at, created_by)
		 VALUES (?,?,?,?,?, ?,?,?,?,?, ?,?,?, ?,?,?,?, ?,?,?)`,
		projectID, projectID, "", lib.TypeProject, 0,
		nil, nil, summary, data, lib.StagePreDataroom,
		"", "", "",
		1, nil, nil, 1,
		now, now, userID,
	)

	// Grant access
	lib.AccessGrant(db, &lib.Access{
		ID:        uuid.New().String(),
		ProjectID: projectID,
		UserID:    userID,
		Role:      lib.RoleIBAdmin,
		Ops:       "rwdm",
		CanGrant:  true,
		GrantedBy: "system",
		GrantedAt: now,
	})

	return projectID
}

// uploadFile performs a multipart file upload
func uploadFile(t *testing.T, client *http.Client, url, token, filename, contentType string, content []byte, formFields map[string]string) *http.Response {
	t.Helper()

	var buf bytes.Buffer
	writer := multipart.NewWriter(&buf)

	// Add form fields
	for key, val := range formFields {
		writer.WriteField(key, val)
	}

	// Add file
	part, err := writer.CreateFormFile("file", filename)
	if err != nil {
		t.Fatalf("create form file: %v", err)
	}
	part.Write(content)
	writer.Close()

	req, _ := http.NewRequest("POST", url, &buf)
	req.Header.Set("Authorization", "Bearer "+token)
	req.Header.Set("Content-Type", writer.FormDataContentType())

	resp, err := client.Do(req)
	if err != nil {
		t.Fatalf("upload request failed: %v", err)
	}
	return resp
}

func TestImportRequestsCSV(t *testing.T) {
	server, db, cfg, cleanup := testServerSetup(t)
	defer cleanup()

	client := &http.Client{}

	// Create user
	userID := uuid.New().String()
	now := time.Now().UnixMilli()
	user := &lib.User{
		UserID:    userID,
		Email:     "import@test.com",
		Name:      "Import Test",
		Password:  "",
		Active:    true,
		CreatedAt: now,
		UpdatedAt: now,
	}
	lib.UserCreate(db, user)

	projectID := createTestProjectWithAccess(t, db, cfg, userID)
	token := getToken(t, client, server.URL, "import@test.com")

	// Create a valid CSV
	csvContent := `Section,Item #,Description,Priority
Financial,1.1,Provide audited financial statements,High
Financial,1.2,Revenue breakdown by product,Medium
Legal,2.1,List of all pending litigation,Critical
Legal,2.2,Employment contracts for executives,Low
HR,3.1,Organization chart,Nice to have`

	resp := uploadFile(t, client, server.URL+"/api/projects/"+projectID+"/requests/import",
		token, "requests.csv", "text/csv", []byte(csvContent), nil)
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		t.Fatalf("expected 200, got %d: %s", resp.StatusCode, string(body))
	}

	var importResp map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&importResp)

	imported := int(importResp["imported"].(float64))
	if imported != 5 {
		t.Errorf("expected 5 imported, got %d", imported)
	}

	skipped := int(importResp["skipped"].(float64))
	if skipped != 0 {
		t.Errorf("expected 0 skipped, got %d", skipped)
	}

	sections := importResp["sections"].([]interface{})
	if len(sections) != 3 {
		t.Errorf("expected 3 sections, got %d: %v", len(sections), sections)
	}
}

func TestImportRequestsXLSX(t *testing.T) {
	server, db, cfg, cleanup := testServerSetup(t)
	defer cleanup()

	client := &http.Client{}

	userID := uuid.New().String()
	now := time.Now().UnixMilli()
	user := &lib.User{
		UserID:    userID,
		Email:     "xlsx@test.com",
		Name:      "XLSX Test",
		Password:  "",
		Active:    true,
		CreatedAt: now,
		UpdatedAt: now,
	}
	lib.UserCreate(db, user)

	projectID := createTestProjectWithAccess(t, db, cfg, userID)
	token := getToken(t, client, server.URL, "xlsx@test.com")

	// Create a minimal valid XLSX
	xlsxContent := createMinimalXLSX([][]string{
		{"Section", "Item #", "Description", "Priority"},
		{"Finance", "F-1", "Cash flow statement", "High"},
		{"Finance", "F-2", "Balance sheet", "Medium"},
	})

	resp := uploadFile(t, client, server.URL+"/api/projects/"+projectID+"/requests/import",
		token, "requests.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
		xlsxContent, nil)
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		t.Fatalf("expected 200, got %d: %s", resp.StatusCode, string(body))
	}

	var importResp map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&importResp)

	imported := int(importResp["imported"].(float64))
	if imported != 2 {
		t.Errorf("expected 2 imported, got %d", imported)
	}
}

// createMinimalXLSX creates a minimal valid XLSX file from rows
func createMinimalXLSX(rows [][]string) []byte {
	var buf bytes.Buffer
	zw := zip.NewWriter(&buf)

	// [Content_Types].xml
	ct := `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
<Default Extension="xml" ContentType="application/xml"/>
<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>
<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>
<Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/>
</Types>`
	w, _ := zw.Create("[Content_Types].xml")
	w.Write([]byte(ct))

	// _rels/.rels
	rels := `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>
</Relationships>`
	w, _ = zw.Create("_rels/.rels")
	w.Write([]byte(rels))

	// xl/_rels/workbook.xml.rels
	wbrels := `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" Target="sharedStrings.xml"/>
</Relationships>`
	w, _ = zw.Create("xl/_rels/workbook.xml.rels")
	w.Write([]byte(wbrels))

	// xl/workbook.xml
	wb := `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
<sheets><sheet name="Sheet1" sheetId="1" r:id="rId1"/></sheets>
</workbook>`
	w, _ = zw.Create("xl/workbook.xml")
	w.Write([]byte(wb))

	// Collect all strings and build shared strings
	var allStrings []string
	stringIndex := make(map[string]int)
	for _, row := range rows {
		for _, cell := range row {
			if _, exists := stringIndex[cell]; !exists {
				stringIndex[cell] = len(allStrings)
				allStrings = append(allStrings, cell)
			}
		}
	}

	// xl/sharedStrings.xml
	ssb := bytes.NewBufferString(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="` + fmt.Sprintf("%d", len(allStrings)) + `" uniqueCount="` + fmt.Sprintf("%d", len(allStrings)) + `">`)
	for _, s := range allStrings {
		ssb.WriteString("<si><t>" + escapeXML(s) + "</t></si>")
	}
	ssb.WriteString("</sst>")
	w, _ = zw.Create("xl/sharedStrings.xml")
	w.Write(ssb.Bytes())

	// xl/worksheets/sheet1.xml
	sheetb := bytes.NewBufferString(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<sheetData>`)
	for ri, row := range rows {
		sheetb.WriteString(fmt.Sprintf(`<row r="%d">`, ri+1))
		for ci, cell := range row {
			colLetter := string(rune('A' + ci))
			cellRef := fmt.Sprintf("%s%d", colLetter, ri+1)
			idx := stringIndex[cell]
			sheetb.WriteString(fmt.Sprintf(`<c r="%s" t="s"><v>%d</v></c>`, cellRef, idx))
		}
		sheetb.WriteString("</row>")
	}
	sheetb.WriteString("</sheetData></worksheet>")
	w, _ = zw.Create("xl/worksheets/sheet1.xml")
	w.Write(sheetb.Bytes())

	zw.Close()
	return buf.Bytes()
}

func escapeXML(s string) string {
	var buf bytes.Buffer
	for _, r := range s {
		switch r {
		case '<':
			buf.WriteString("&lt;")
		case '>':
			buf.WriteString("&gt;")
		case '&':
			buf.WriteString("&amp;")
		case '"':
			buf.WriteString("&quot;")
		case '\'':
			buf.WriteString("&apos;")
		default:
			buf.WriteRune(r)
		}
	}
	return buf.String()
}

func TestImportSmartHeaderDetection(t *testing.T) {
	server, db, cfg, cleanup := testServerSetup(t)
	defer cleanup()

	client := &http.Client{}

	userID := uuid.New().String()
	now := time.Now().UnixMilli()
	user := &lib.User{
		UserID:    userID,
		Email:     "smartheader@test.com",
		Name:      "Smart Header",
		Password:  "",
		Active:    true,
		CreatedAt: now,
		UpdatedAt: now,
	}
	lib.UserCreate(db, user)

	projectID := createTestProjectWithAccess(t, db, cfg, userID)
	token := getToken(t, client, server.URL, "smartheader@test.com")

	// CSV with 3 title rows before the actual header
	csvContent := `Project XYZ Due Diligence Request List
Confidential - Internal Use Only
Generated: 2026-02-28
Section,Item #,Information Requested,Priority
Financial,1.1,Audited financials 3 years,High
Financial,1.2,Monthly management reports,Medium`

	resp := uploadFile(t, client, server.URL+"/api/projects/"+projectID+"/requests/import",
		token, "with-title-rows.csv", "text/csv", []byte(csvContent), nil)
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		t.Fatalf("expected 200, got %d: %s", resp.StatusCode, string(body))
	}

	var importResp map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&importResp)

	// Should detect header at row 4 (index 3) and import 2 rows
	imported := int(importResp["imported"].(float64))
	if imported != 2 {
		t.Errorf("expected 2 imported (header detection), got %d", imported)
	}
}

func TestImportModeReplace(t *testing.T) {
	server, db, cfg, cleanup := testServerSetup(t)
	defer cleanup()

	client := &http.Client{}

	userID := uuid.New().String()
	now := time.Now().UnixMilli()
	user := &lib.User{
		UserID:    userID,
		Email:     "replace@test.com",
		Name:      "Replace Test",
		Password:  "",
		Active:    true,
		CreatedAt: now,
		UpdatedAt: now,
	}
	lib.UserCreate(db, user)

	projectID := createTestProjectWithAccess(t, db, cfg, userID)
	token := getToken(t, client, server.URL, "replace@test.com")

	// First import
	csv1 := `Section,Item #,Description,Priority
Finance,1,First batch item 1,High
Finance,2,First batch item 2,Medium`

	resp := uploadFile(t, client, server.URL+"/api/projects/"+projectID+"/requests/import",
		token, "batch1.csv", "text/csv", []byte(csv1), map[string]string{"mode": "add"})
	resp.Body.Close()

	// Second import with mode=replace
	csv2 := `Section,Item #,Description,Priority
Legal,A,Second batch only,High`

	resp = uploadFile(t, client, server.URL+"/api/projects/"+projectID+"/requests/import",
		token, "batch2.csv", "text/csv", []byte(csv2), map[string]string{"mode": "replace"})
	resp.Body.Close()

	// List requests - should only have 1 (from second batch)
	req, _ := http.NewRequest("GET", server.URL+"/api/projects/"+projectID+"/requests", nil)
	req.Header.Set("Authorization", "Bearer "+token)
	resp, err := client.Do(req)
	if err != nil {
		t.Fatalf("list requests failed: %v", err)
	}
	defer resp.Body.Close()

	var requests []map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&requests)

	if len(requests) != 1 {
		t.Errorf("after replace, expected 1 request, got %d", len(requests))
	}
	if len(requests) > 0 && requests[0]["section"] != "Legal" {
		t.Errorf("expected Legal section, got %v", requests[0]["section"])
	}
}

func TestImportModeAdd(t *testing.T) {
	server, db, cfg, cleanup := testServerSetup(t)
	defer cleanup()

	client := &http.Client{}

	userID := uuid.New().String()
	now := time.Now().UnixMilli()
	user := &lib.User{
		UserID:    userID,
		Email:     "addmode@test.com",
		Name:      "Add Mode",
		Password:  "",
		Active:    true,
		CreatedAt: now,
		UpdatedAt: now,
	}
	lib.UserCreate(db, user)

	projectID := createTestProjectWithAccess(t, db, cfg, userID)
	token := getToken(t, client, server.URL, "addmode@test.com")

	// First import
	csv1 := `Section,Item #,Description,Priority
Finance,1,First item,High`

	resp := uploadFile(t, client, server.URL+"/api/projects/"+projectID+"/requests/import",
		token, "add1.csv", "text/csv", []byte(csv1), map[string]string{"mode": "add"})
	resp.Body.Close()

	// Second import with mode=add (accumulate)
	csv2 := `Section,Item #,Description,Priority
Legal,2,Second item,Medium`

	resp = uploadFile(t, client, server.URL+"/api/projects/"+projectID+"/requests/import",
		token, "add2.csv", "text/csv", []byte(csv2), map[string]string{"mode": "add"})
	resp.Body.Close()

	// List requests - should have 2 (accumulated)
	req, _ := http.NewRequest("GET", server.URL+"/api/projects/"+projectID+"/requests", nil)
	req.Header.Set("Authorization", "Bearer "+token)
	resp, err := client.Do(req)
	if err != nil {
		t.Fatalf("list requests failed: %v", err)
	}
	defer resp.Body.Close()

	var requests []map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&requests)

	if len(requests) != 2 {
		t.Errorf("after add mode, expected 2 requests, got %d", len(requests))
	}
}

func TestListRequests(t *testing.T) {
	server, db, cfg, cleanup := testServerSetup(t)
	defer cleanup()

	client := &http.Client{}

	userID := uuid.New().String()
	now := time.Now().UnixMilli()
	user := &lib.User{
		UserID:    userID,
		Email:     "list@test.com",
		Name:      "List Test",
		Password:  "",
		Active:    true,
		CreatedAt: now,
		UpdatedAt: now,
	}
	lib.UserCreate(db, user)

	projectID := createTestProjectWithAccess(t, db, cfg, userID)
	token := getToken(t, client, server.URL, "list@test.com")

	// Import some requests
	csv := `Section,Item #,Description,Priority
Alpha,A-1,First alpha item,High
Alpha,A-2,Second alpha item,Medium
Beta,B-1,First beta item,Low`

	resp := uploadFile(t, client, server.URL+"/api/projects/"+projectID+"/requests/import",
		token, "list.csv", "text/csv", []byte(csv), nil)
	resp.Body.Close()

	// List requests
	req, _ := http.NewRequest("GET", server.URL+"/api/projects/"+projectID+"/requests", nil)
	req.Header.Set("Authorization", "Bearer "+token)
	resp, err := client.Do(req)
	if err != nil {
		t.Fatalf("list requests failed: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		t.Fatalf("expected 200, got %d", resp.StatusCode)
	}

	var requests []map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&requests)

	if len(requests) != 3 {
		t.Errorf("expected 3 requests, got %d", len(requests))
	}

	// Verify structure
	for _, r := range requests {
		if r["entry_id"] == nil || r["entry_id"] == "" {
			t.Error("request should have entry_id")
		}
		if r["section"] == nil {
			t.Error("request should have section")
		}
		if r["priority"] == nil {
			t.Error("request should have priority")
		}
		if r["status"] == nil {
			t.Error("request should have status")
		}
	}
}

func TestPriorityNormalization(t *testing.T) {
	server, db, cfg, cleanup := testServerSetup(t)
	defer cleanup()

	client := &http.Client{}

	userID := uuid.New().String()
	now := time.Now().UnixMilli()
	user := &lib.User{
		UserID:    userID,
		Email:     "priority@test.com",
		Name:      "Priority Test",
		Password:  "",
		Active:    true,
		CreatedAt: now,
		UpdatedAt: now,
	}
	lib.UserCreate(db, user)

	projectID := createTestProjectWithAccess(t, db, cfg, userID)
	token := getToken(t, client, server.URL, "priority@test.com")

	// CSV with various priority formats
	csv := `Section,Item #,Description,Priority
Test,1,Critical priority,CRITICAL
Test,2,Nice to have priority,Nice to have
Test,3,Normal priority,Normal
Test,4,Urgent priority,Urgent
Test,5,High priority,High
Test,6,Low priority,Low
Test,7,Optional priority,optional`

	resp := uploadFile(t, client, server.URL+"/api/projects/"+projectID+"/requests/import",
		token, "priority.csv", "text/csv", []byte(csv), nil)
	resp.Body.Close()

	// List and verify priority normalization
	req, _ := http.NewRequest("GET", server.URL+"/api/projects/"+projectID+"/requests", nil)
	req.Header.Set("Authorization", "Bearer "+token)
	resp, err := client.Do(req)
	if err != nil {
		t.Fatalf("list requests failed: %v", err)
	}
	defer resp.Body.Close()

	var requests []map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&requests)

	expected := map[string]string{
		"Critical priority":       "high", // CRITICAL → high
		"Nice to have priority":   "low",  // Nice to have → low
		"Normal priority":         "medium",
		"Urgent priority":         "high", // Urgent → high
		"High priority":           "high",
		"Low priority":            "low",
		"Optional priority":       "low", // optional → low
	}

	for _, r := range requests {
		title := r["title"].(string)
		if expectedPri, ok := expected[title]; ok {
			if r["priority"] != expectedPri {
				t.Errorf("%s: expected priority %q, got %q", title, expectedPri, r["priority"])
			}
		}
	}
}

func TestImportNoFile(t *testing.T) {
	server, db, cfg, cleanup := testServerSetup(t)
	defer cleanup()

	client := &http.Client{}

	userID := uuid.New().String()
	now := time.Now().UnixMilli()
	user := &lib.User{
		UserID:    userID,
		Email:     "nofile@test.com",
		Name:      "No File",
		Password:  "",
		Active:    true,
		CreatedAt: now,
		UpdatedAt: now,
	}
	lib.UserCreate(db, user)

	projectID := createTestProjectWithAccess(t, db, cfg, userID)
	token := getToken(t, client, server.URL, "nofile@test.com")

	// Try import without file
	req, _ := http.NewRequest("POST", server.URL+"/api/projects/"+projectID+"/requests/import", nil)
	req.Header.Set("Authorization", "Bearer "+token)
	req.Header.Set("Content-Type", "multipart/form-data")
	resp, err := client.Do(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusBadRequest {
		t.Errorf("expected 400 for missing file, got %d", resp.StatusCode)
	}
}

func TestImportAccessDenied(t *testing.T) {
	server, db, cfg, cleanup := testServerSetup(t)
	defer cleanup()

	client := &http.Client{}

	// Create project owner
	ownerID := uuid.New().String()
	now := time.Now().UnixMilli()
	owner := &lib.User{
		UserID:    ownerID,
		Email:     "owner@test.com",
		Name:      "Owner",
		Password:  "",
		Active:    true,
		CreatedAt: now,
		UpdatedAt: now,
	}
	lib.UserCreate(db, owner)
	projectID := createTestProjectWithAccess(t, db, cfg, ownerID)

	// Create buyer (read-only, no write access)
	buyerID := uuid.New().String()
	buyer := &lib.User{
		UserID:    buyerID,
		Email:     "buyer-readonly@test.com",
		Name:      "Buyer",
		Password:  "",
		Active:    true,
		CreatedAt: now,
		UpdatedAt: now,
	}
	lib.UserCreate(db, buyer)
	lib.AccessGrant(db, &lib.Access{
		ID:        uuid.New().String(),
		ProjectID: projectID,
		UserID:    buyerID,
		Role:      lib.RoleBuyerMember,
		Ops:       "r", // read only
		CanGrant:  false,
		GrantedBy: "system",
		GrantedAt: now,
	})

	buyerToken := getToken(t, client, server.URL, "buyer-readonly@test.com")

	csv := `Section,Item #,Description,Priority
Test,1,Test item,High`

	resp := uploadFile(t, client, server.URL+"/api/projects/"+projectID+"/requests/import",
		buyerToken, "denied.csv", "text/csv", []byte(csv), nil)
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusForbidden {
		t.Errorf("expected 403 for buyer import, got %d", resp.StatusCode)
	}
}

func TestListRequestsAccessDenied(t *testing.T) {
	server, db, cfg, cleanup := testServerSetup(t)
	defer cleanup()

	client := &http.Client{}

	// Create project
	ownerID := uuid.New().String()
	now := time.Now().UnixMilli()
	owner := &lib.User{
		UserID:    ownerID,
		Email:     "listowner@test.com",
		Name:      "List Owner",
		Password:  "",
		Active:    true,
		CreatedAt: now,
		UpdatedAt: now,
	}
	lib.UserCreate(db, owner)
	projectID := createTestProjectWithAccess(t, db, cfg, ownerID)

	// Create user with no access
	noAccessID := uuid.New().String()
	noAccess := &lib.User{
		UserID:    noAccessID,
		Email:     "noaccess-list@test.com",
		Name:      "No Access",
		Password:  "",
		Active:    true,
		CreatedAt: now,
		UpdatedAt: now,
	}
	lib.UserCreate(db, noAccess)

	noAccessToken := getToken(t, client, server.URL, "noaccess-list@test.com")

	req, _ := http.NewRequest("GET", server.URL+"/api/projects/"+projectID+"/requests", nil)
	req.Header.Set("Authorization", "Bearer "+noAccessToken)
	resp, err := client.Do(req)
	if err != nil {
		t.Fatalf("request failed: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusForbidden {
		t.Errorf("expected 403 for no access list, got %d", resp.StatusCode)
	}
}

// This test file doesn't exist in the original but is mentioned, so skip it
func init() {
	// Ensure tests don't fail due to missing template directory
	os.MkdirAll("/tmp/dealspace-test-templates", 0755)
}
