package notes

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

	"github.com/gin-gonic/gin"
)

func setupTestRouter(t *testing.T) (*gin.Engine, *Service) {
	gin.SetMode(gin.TestMode)
	router := gin.New()
	db := setupTestDB(t)
	service := NewService(db)
	handler := NewHandler(service)
	handler.RegisterRoutes(router.Group("/api"))
	return router, service
}

func TestHandler_CreateNote(t *testing.T) {
	router, _ := setupTestRouter(t)

	// Test creating a note
	note := map[string]interface{}{
		"title":   "Test Note",
		"content": "Test content with [[Another Note]]",
	}
	body, _ := json.Marshal(note)
	req := httptest.NewRequest("POST", "/api/notes", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("Expected status %d, got %d", http.StatusOK, w.Code)
	}

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

	if response["title"] != note["title"] {
		t.Errorf("Expected title %q, got %q", note["title"], response["title"])
	}
}

func TestHandler_GetNote(t *testing.T) {
	router, service := setupTestRouter(t)

	// Create a test note
	note := &Note{
		Title:   "Test Note",
		Content: "Test content",
	}
	if err := service.Create(note); err != nil {
		t.Fatalf("Failed to create test note: %v", err)
	}

	// Test getting the note
	req := httptest.NewRequest("GET", "/api/notes/"+note.ID, nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("Expected status %d, got %d", http.StatusOK, w.Code)
	}

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

	if response["title"] != note.Title {
		t.Errorf("Expected title %q, got %q", note.Title, response["title"])
	}

	// Test getting non-existent note
	req = httptest.NewRequest("GET", "/api/notes/non-existent", nil)
	w = httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusNotFound {
		t.Errorf("Expected status %d, got %d", http.StatusNotFound, w.Code)
	}
}

func TestHandler_ListNotes(t *testing.T) {
	router, service := setupTestRouter(t)

	// Create some test notes
	notes := []*Note{
		{Title: "First Note", Content: "First content"},
		{Title: "Second Note", Content: "Second content"},
	}
	for _, note := range notes {
		if err := service.Create(note); err != nil {
			t.Fatalf("Failed to create test note: %v", err)
		}
	}

	// Test listing notes
	req := httptest.NewRequest("GET", "/api/notes", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("Expected status %d, got %d", http.StatusOK, w.Code)
	}

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

	if len(response) != len(notes) {
		t.Errorf("Expected %d notes, got %d", len(notes), len(response))
	}
}

func TestHandler_UpdateNote(t *testing.T) {
	router, service := setupTestRouter(t)

	// Create a test note
	note := &Note{
		Title:   "Original Title",
		Content: "Original content",
	}
	if err := service.Create(note); err != nil {
		t.Fatalf("Failed to create test note: %v", err)
	}

	// Test updating the note
	update := map[string]interface{}{
		"title":   "Updated Title",
		"content": "Updated content with [[Link]]",
	}
	body, _ := json.Marshal(update)
	req := httptest.NewRequest("PUT", "/api/notes/"+note.ID, bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("Expected status %d, got %d", http.StatusOK, w.Code)
	}

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

	if response["title"] != update["title"] {
		t.Errorf("Expected title %q, got %q", update["title"], response["title"])
	}
}

func TestHandler_DeleteNote(t *testing.T) {
	router, service := setupTestRouter(t)

	// Create a test note
	note := &Note{
		Title:   "Test Note",
		Content: "Test content",
	}
	if err := service.Create(note); err != nil {
		t.Fatalf("Failed to create test note: %v", err)
	}

	// Test deleting the note
	req := httptest.NewRequest("DELETE", "/api/notes/"+note.ID, nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("Expected status %d, got %d", http.StatusOK, w.Code)
	}

	// Verify note is deleted
	req = httptest.NewRequest("GET", "/api/notes/"+note.ID, nil)
	w = httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusNotFound {
		t.Errorf("Expected status %d, got %d", http.StatusNotFound, w.Code)
	}
}

func TestHandler_ResetNotes(t *testing.T) {
	router, service := setupTestRouter(t)

	// Create some test notes
	notes := []*Note{
		{Title: "First Note", Content: "First content"},
		{Title: "Second Note", Content: "Second content"},
	}
	for _, note := range notes {
		if err := service.Create(note); err != nil {
			t.Fatalf("Failed to create test note: %v", err)
		}
	}

	// Test resetting notes
	req := httptest.NewRequest("POST", "/api/test/reset", nil)
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("Expected status %d, got %d", http.StatusOK, w.Code)
	}

	// Verify all notes are deleted
	req = httptest.NewRequest("GET", "/api/notes", nil)
	w = httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("Expected status %d, got %d", http.StatusOK, w.Code)
	}

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

	if len(response) != 0 {
		t.Errorf("Expected empty notes list, got %d notes", len(response))
	}
}