package api

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

	"github.com/markdown-editor/internal/storage"
	"github.com/markdown-editor/pkg/logger"
)

type bytesReader struct {
	bytes []byte
}

func (r *bytesReader) Read(p []byte) (n int, err error) {
	if len(r.bytes) == 0 {
		return 0, io.EOF
	}
	n = copy(p, r.bytes)
	r.bytes = r.bytes[n:]
	return n, nil
}

func (r *bytesReader) Close() error {
	return nil
}

func setupTestServer(t *testing.T) (*Server, string) {
	// Initialize logger
	logger.Init()

	// Create temporary directory for test data
	tempDir := t.TempDir()
	
	// Initialize storage
	s := storage.NewStorage(tempDir)
	
	// Create server
	server, err := NewServer(tempDir, "127.0.0.1", 0)
	if err != nil {
		t.Fatalf("Failed to create server: %v", err)
	}
	
	// Get actual port assigned by ListenAndServe
	router := http.NewServeMux()
	router.HandleFunc("/api/files", server.handleFiles)
	router.HandleFunc("/api/files/", server.handleFiles)
	router.HandleFunc("/", server.handleFrontend)
	
	server.storage = s
	server.port = 0 // 0 means assign any available port
	
	return server, tempDir
}

func TestHandleGetFiles(t *testing.T) {
	server, dataDir := setupTestServer(t)
	
	// Create test files
	content := "Test content"
	testFiles := []string{"test1.md", "test2.md"}
	
	for _, filename := range testFiles {
		path := filepath.Join(dataDir, filename)
		if err := os.WriteFile(path, []byte(content), 0644); err != nil {
			t.Fatalf("Failed to create test file: %v", err)
		}
	}
	
	req := httptest.NewRequest("GET", "/api/files", nil)
	w := httptest.NewRecorder()
	
	server.handleGetFiles(w, req)
	
	if w.Code != http.StatusOK {
		t.Errorf("Expected status 200, got %d", w.Code)
	}
	
	var files []string
	if err := json.NewDecoder(w.Body).Decode(&files); err != nil {
		t.Fatalf("Failed to decode response: %v", err)
	}
	
	if len(files) != 2 {
		t.Errorf("Expected 2 files, got %d", len(files))
	}
}

func TestHandleCreateFile(t *testing.T) {
	server, dataDir := setupTestServer(t)
	
	reqBody := map[string]string{
		"content": "Test content",
		"name":    "newfile.md",
	}
	reqBodyBytes, _ := json.Marshal(reqBody)
	
	req := httptest.NewRequest("POST", "/api/files", nil)
	req.Header.Set("Content-Type", "application/json")
	req.Body = &bytesReader{bytes: reqBodyBytes}
	
	w := httptest.NewRecorder()
	server.handleCreateFile(w, req)
	
	if w.Code != http.StatusCreated {
		t.Errorf("Expected status 201, got %d", w.Code)
	}
	
	// Verify file was created
	path := filepath.Join(dataDir, "newfile.md")
	if _, err := os.Stat(path); os.IsNotExist(err) {
		t.Error("File was not created")
	}
}

func TestHandleUpdateFile(t *testing.T) {
	server, dataDir := setupTestServer(t)
	
	// Create test file first
	filename := "updatefile.md"
	path := filepath.Join(dataDir, filename)
	os.WriteFile(path, []byte("Original content"), 0644)
	
	reqBody := map[string]string{
		"content": "Updated content",
	}
	reqBodyBytes, _ := json.Marshal(reqBody)
	
	req := httptest.NewRequest("PUT", "/api/files/"+filename, nil)
	req.Header.Set("Content-Type", "application/json")
	req.Body = &bytesReader{bytes: reqBodyBytes}
	
	w := httptest.NewRecorder()
	server.handleUpdateFile(w, req)
	
	if w.Code != http.StatusOK {
		t.Errorf("Expected status 200, got %d", w.Code)
	}
	
	// Verify file content was updated
	newContent, err := os.ReadFile(path)
	if err != nil {
		t.Fatalf("Failed to read file: %v", err)
	}
	if string(newContent) != "Updated content" {
		t.Error("File content was not updated correctly")
	}
}

func TestHandleDeleteFile(t *testing.T) {
	server, dataDir := setupTestServer(t)
	
	// Create test file
	filename := "deletefile.md"
	path := filepath.Join(dataDir, filename)
	os.WriteFile(path, []byte("Test content"), 0644)
	
	req := httptest.NewRequest("DELETE", "/api/files/"+filename, nil)
	w := httptest.NewRecorder()
	
	server.handleDeleteFile(w, req)
	
	if w.Code != http.StatusOK {
		t.Errorf("Expected status 200, got %d", w.Code)
	}
	
	// Verify file was deleted
	if _, err := os.Stat(path); !os.IsNotExist(err) {
		t.Error("File was not deleted")
	}
}

func TestHandleStaticFiles(t *testing.T) {
	server, _ := setupTestServer(t)
	
	// Try to serve static file
	req := httptest.NewRequest("GET", "/static/index.html", nil)
	w := httptest.NewRecorder()
	
	server.handleFrontend(w, req)
	
	// Should return 301 redirect or 200 for index.html
	if w.Code != http.StatusOK && w.Code != http.StatusMovedPermanently {
		t.Errorf("Expected status 200 or 301, got %d", w.Code)
	}
}
