package api

import (
	"net/http"
	"testing"
	"time"

	cfg "erupe-ce/config"
	"go.uber.org/zap"
)

func TestNewAPIServer(t *testing.T) {
	logger := NewTestLogger(t)
	defer func() { _ = logger.Sync() }()

	cfg := NewTestConfig()
	config := &Config{
		Logger:      logger,
		DB:          nil, // Database can be nil for this test
		ErupeConfig: cfg,
	}

	server := NewAPIServer(config)

	if server == nil {
		t.Fatal("NewAPIServer returned nil")
	}

	if server.logger != logger {
		t.Error("Logger not properly assigned")
	}

	if server.erupeConfig != cfg {
		t.Error("ErupeConfig not properly assigned")
	}

	if server.httpServer == nil {
		t.Error("HTTP server not initialized")
	}

	if server.isShuttingDown != false {
		t.Error("Server should not be shutting down on creation")
	}
}

func TestNewAPIServerConfig(t *testing.T) {
	logger := NewTestLogger(t)
	defer func() { _ = logger.Sync() }()

	cfg := &cfg.Config{
		API: cfg.API{
			Port:        9999,
			PatchServer: "http://example.com",
			Banners:     []cfg.APISignBanner{},
			Messages:    []cfg.APISignMessage{},
			Links:       []cfg.APISignLink{},
		},
		Screenshots: cfg.ScreenshotsOptions{
			Enabled:       false,
			OutputDir:     "/custom/path",
			UploadQuality: 95,
		},
		DebugOptions: cfg.DebugOptions{
			MaxLauncherHR: true,
		},
		GameplayOptions: cfg.GameplayOptions{
			MezFesSoloTickets: 200,
		},
	}

	config := &Config{
		Logger:      logger,
		DB:          nil,
		ErupeConfig: cfg,
	}

	server := NewAPIServer(config)

	if server.erupeConfig.API.Port != 9999 {
		t.Errorf("API port = %d, want 9999", server.erupeConfig.API.Port)
	}

	if server.erupeConfig.API.PatchServer != "http://example.com" {
		t.Errorf("PatchServer = %s, want http://example.com", server.erupeConfig.API.PatchServer)
	}

	if server.erupeConfig.Screenshots.UploadQuality != 95 {
		t.Errorf("UploadQuality = %d, want 95", server.erupeConfig.Screenshots.UploadQuality)
	}
}

func TestAPIServerStart(t *testing.T) {
	// Note: This test can be flaky in CI environments
	// It attempts to start an actual HTTP server

	logger := NewTestLogger(t)
	defer func() { _ = logger.Sync() }()

	cfg := NewTestConfig()
	cfg.API.Port = 18888 // Use a high port less likely to be in use

	config := &Config{
		Logger:      logger,
		DB:          nil,
		ErupeConfig: cfg,
	}

	server := NewAPIServer(config)

	// Start server
	err := server.Start()
	if err != nil {
		t.Logf("Start error (may be expected if port in use): %v", err)
		// Don't fail hard, as this might be due to port binding issues in test environment
		return
	}

	// Give the server a moment to start
	time.Sleep(100 * time.Millisecond)

	// Check that the server is running by making a request
	resp, err := http.Get("http://localhost:18888/launcher")
	if err != nil {
		// This might fail if the server didn't start properly or port is blocked
		t.Logf("Failed to connect to server: %v", err)
	} else {
		defer func() { _ = resp.Body.Close() }()
		if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNotFound {
			t.Logf("Unexpected status code: %d", resp.StatusCode)
		}
	}

	// Shutdown the server
	done := make(chan bool, 1)
	go func() {
		server.Shutdown()
		done <- true
	}()

	// Wait for shutdown with timeout
	select {
	case <-done:
		t.Log("Server shutdown successfully")
	case <-time.After(10 * time.Second):
		t.Error("Server shutdown timeout")
	}
}

func TestAPIServerShutdown(t *testing.T) {
	logger := NewTestLogger(t)
	defer func() { _ = logger.Sync() }()

	cfg := NewTestConfig()
	cfg.API.Port = 18889

	config := &Config{
		Logger:      logger,
		DB:          nil,
		ErupeConfig: cfg,
	}

	server := NewAPIServer(config)

	// Try to shutdown without starting (should not panic)
	server.Shutdown()

	// Verify the shutdown flag is set
	server.Lock()
	if !server.isShuttingDown {
		t.Error("isShuttingDown should be true after Shutdown()")
	}
	server.Unlock()
}

func TestAPIServerShutdownSetsFlag(t *testing.T) {
	logger := NewTestLogger(t)
	defer func() { _ = logger.Sync() }()

	cfg := NewTestConfig()
	config := &Config{
		Logger:      logger,
		DB:          nil,
		ErupeConfig: cfg,
	}

	server := NewAPIServer(config)

	if server.isShuttingDown {
		t.Error("Server should not be shutting down initially")
	}

	server.Shutdown()

	server.Lock()
	isShutting := server.isShuttingDown
	server.Unlock()

	if !isShutting {
		t.Error("isShuttingDown flag should be set after Shutdown()")
	}
}

func TestAPIServerConcurrentShutdown(t *testing.T) {
	logger := NewTestLogger(t)
	defer func() { _ = logger.Sync() }()

	cfg := NewTestConfig()
	config := &Config{
		Logger:      logger,
		DB:          nil,
		ErupeConfig: cfg,
	}

	server := NewAPIServer(config)

	// Try shutting down from multiple goroutines concurrently
	done := make(chan bool, 3)

	for i := 0; i < 3; i++ {
		go func() {
			server.Shutdown()
			done <- true
		}()
	}

	// Wait for all goroutines to complete
	for i := 0; i < 3; i++ {
		select {
		case <-done:
		case <-time.After(5 * time.Second):
			t.Error("Timeout waiting for shutdown")
		}
	}

	server.Lock()
	if !server.isShuttingDown {
		t.Error("Server should be shutting down after concurrent shutdown calls")
	}
	server.Unlock()
}

func TestAPIServerMutex(t *testing.T) {
	logger := NewTestLogger(t)
	defer func() { _ = logger.Sync() }()

	cfg := NewTestConfig()
	config := &Config{
		Logger:      logger,
		DB:          nil,
		ErupeConfig: cfg,
	}

	server := NewAPIServer(config)

	// Verify that the server has mutex functionality
	server.Lock()
	isLocked := true
	server.Unlock()

	if !isLocked {
		t.Error("Mutex locking/unlocking failed")
	}
}

func TestAPIServerHTTPServerInitialization(t *testing.T) {
	logger := NewTestLogger(t)
	defer func() { _ = logger.Sync() }()

	cfg := NewTestConfig()
	config := &Config{
		Logger:      logger,
		DB:          nil,
		ErupeConfig: cfg,
	}

	server := NewAPIServer(config)

	if server.httpServer == nil {
		t.Fatal("HTTP server should be initialized")
	}

	if server.httpServer.Addr != "" {
		t.Logf("HTTP server address initially set: %s", server.httpServer.Addr)
	}
}

func BenchmarkNewAPIServer(b *testing.B) {
	logger, _ := zap.NewDevelopment()
	defer func() { _ = logger.Sync() }()

	cfg := NewTestConfig()
	config := &Config{
		Logger:      logger,
		DB:          nil,
		ErupeConfig: cfg,
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_ = NewAPIServer(config)
	}
}
