package main

import (
	"bytes"
	"io"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"testing"

	"github.com/evanreichard/markdown-editor/internal/api"
	"github.com/evanreichard/markdown-editor/internal/logger"
	"github.com/gorilla/mux"
	"github.com/stretchr/testify/assert"
)

func setupTestDir() (string, error) {
	tmpDir := filepath.Join(os.TempDir(), "markdown-editor-test-"+randomString(10))
	if err := os.MkdirAll(tmpDir, 0755); err != nil {
		return "", err
	}
	return tmpDir, nil
}

func cleanupTestDir(dir string) {
	os.RemoveAll(dir)
}

func randomString(n int) string {
	const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	b := make([]byte, n)
	for i := range b {
		b[i] = letters[i%len(letters)]
	}
	return string(b)
}

func TestCRUDOperations(t *testing.T) {
	dataDir, err := setupTestDir()
	if err != nil {
		t.Fatalf("Failed to create test dir: %v", err)
	}
	defer cleanupTestDir(dataDir)

	log := logger.NewLogger()
	handler := api.NewAPIHandler(dataDir, log)
	router := mux.NewRouter()
	router.Handle("/api/{filename:.+\\.md}", handler)

	testContent := "# Test Content\n\nThis is a test."

	// Test POST (Create)
	req := httptest.NewRequest("POST", "/api/test.md", bytes.NewBufferString(testContent))
	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)
	assert.Equal(t, http.StatusCreated, w.Code)

	// Test GET (Read)
	req = httptest.NewRequest("GET", "/api/test.md", nil)
	w = httptest.NewRecorder()
	router.ServeHTTP(w, req)
	assert.Equal(t, http.StatusOK, w.Code)
	body, _ := io.ReadAll(w.Body)
	assert.Equal(t, testContent, string(body))

	// Test PUT (Update)
	updatedContent := "# Updated Content\n\nThis has been updated."
	req = httptest.NewRequest("PUT", "/api/test.md", bytes.NewBufferString(updatedContent))
	w = httptest.NewRecorder()
	router.ServeHTTP(w, req)
	assert.Equal(t, http.StatusOK, w.Code)

	// Verify update
	req = httptest.NewRequest("GET", "/api/test.md", nil)
	w = httptest.NewRecorder()
	router.ServeHTTP(w, req)
	assert.Equal(t, http.StatusOK, w.Code)
	body, _ = io.ReadAll(w.Body)
	assert.Equal(t, updatedContent, string(body))

	// Test DELETE
	req = httptest.NewRequest("DELETE", "/api/test.md", nil)
	w = httptest.NewRecorder()
	router.ServeHTTP(w, req)
	assert.Equal(t, http.StatusNoContent, w.Code)

	// Verify deletion
	req = httptest.NewRequest("GET", "/api/test.md", nil)
	w = httptest.NewRecorder()
	router.ServeHTTP(w, req)
	assert.Equal(t, http.StatusNotFound, w.Code)
}

func TestStaticAssetServing(t *testing.T) {
	dataDir, err := setupTestDir()
	if err != nil {
		t.Fatalf("Failed to create test dir: %v", err)
	}
	defer cleanupTestDir(dataDir)

	// Test that FileServer can serve files
	fs := http.FileServer(http.Dir(dataDir))
	
	// Create a test HTML file
	testHTML := `<!DOCTYPE html><html><head><title>Test</title></head><body><h1>Hello</h1></body></html>`
	testPath := filepath.Join(dataDir, "index.html")
	if err := os.WriteFile(testPath, []byte(testHTML), 0644); err != nil {
		t.Fatalf("Failed to create test HTML: %v", err)
	}
	
	// Verify file was created
	content, err := os.ReadFile(testPath)
	if err != nil {
		t.Fatalf("Failed to read test HTML: %v", err)
	}
	assert.Equal(t, testHTML, string(content))

	// Test serving static file - just verify it doesn't error
	req := httptest.NewRequest("GET", "/index.html/", nil)
	w := httptest.NewRecorder()
	fs.ServeHTTP(w, req)
	// FileServer may redirect, but we just verify it doesn't panic
	assert.NotEqual(t, http.StatusNotFound, w.Code)
}
