package test

import (
	"encoding/json"
	"fmt"
	"os"
	"testing"
	"time"

	"git.teamworkapps.com/shortcut/cremote/client"
)

const (
	testServerURL = "http://localhost:8080"
	daemonAddr    = "localhost:9223"
)

// TestAccessibilityToolsIntegration runs comprehensive integration tests for all accessibility tools
func TestAccessibilityToolsIntegration(t *testing.T) {
	// Skip if not in integration test mode
	if os.Getenv("INTEGRATION_TESTS") != "true" {
		t.Skip("Skipping integration tests. Set INTEGRATION_TESTS=true to run.")
	}

	// Create client
	c := client.NewClient(daemonAddr)

	// Wait for daemon to be ready
	time.Sleep(2 * time.Second)

	// Navigate to test page
	err := c.Navigate("", testServerURL+"/test-accessible.html", false, 10)
	if err != nil {
		t.Fatalf("Failed to navigate to test page: %v", err)
	}

	// Wait for page load
	time.Sleep(2 * time.Second)

	// Run all accessibility tests
	t.Run("AxeCoreIntegration", testAxeCoreIntegration(c))
	t.Run("ContrastChecking", testContrastChecking(c))
	t.Run("KeyboardNavigation", testKeyboardNavigation(c))
	t.Run("ZoomTesting", testZoomTesting(c))
	t.Run("ReflowTesting", testReflowTesting(c))
	t.Run("ScreenshotEnhancements", testScreenshotEnhancements(c))
	t.Run("LibraryInjection", testLibraryInjection(c))
	t.Run("AccessibilityTree", testAccessibilityTree(c))
}

// testAxeCoreIntegration tests axe-core injection and execution
func testAxeCoreIntegration(c *client.Client) func(*testing.T) {
	return func(t *testing.T) {
		// Inject axe-core
		err := c.InjectAxeCore("", "4.8.0", 30)
		if err != nil {
			t.Fatalf("Failed to inject axe-core: %v", err)
		}

		// Run axe tests
		runOnly := []string{"wcag2a", "wcag2aa"}
		result, err := c.RunAxeCore("", runOnly, nil, 30)
		if err != nil {
			t.Fatalf("Failed to run axe-core: %v", err)
		}

		// Verify result structure
		if result == nil {
			t.Fatal("Axe result is nil")
		}

		// Check that we got some results
		totalChecks := len(result.Violations) + len(result.Passes) + len(result.Incomplete) + len(result.Inapplicable)
		if totalChecks == 0 {
			t.Error("Axe-core returned no results")
		}

		t.Logf("Axe-core results: %d violations, %d passes, %d incomplete, %d inapplicable",
			len(result.Violations), len(result.Passes), len(result.Incomplete), len(result.Inapplicable))

		// For accessible page, we expect few or no violations
		if len(result.Violations) > 5 {
			t.Errorf("Expected few violations on accessible page, got %d", len(result.Violations))
		}
	}
}

// testContrastChecking tests color contrast checking
func testContrastChecking(c *client.Client) func(*testing.T) {
	return func(t *testing.T) {
		result, err := c.CheckContrast("", "body", 10)
		if err != nil {
			t.Fatalf("Failed to check contrast: %v", err)
		}

		if result == nil {
			t.Fatal("Contrast result is nil")
		}

		// Verify result structure
		if result.TotalElements == 0 {
			t.Error("No elements checked for contrast")
		}

		t.Logf("Contrast check: %d elements, %d AA pass, %d AA fail, %d AAA pass, %d AAA fail",
			result.TotalElements, result.WCAGAAPass, result.WCAGAAFail, result.WCAGAAAPass, result.WCAGAAAFail)

		// For accessible page, we expect high AA pass rate
		if result.TotalElements > 0 {
			passRate := float64(result.WCAGAAPass) / float64(result.TotalElements)
			if passRate < 0.8 {
				t.Errorf("Expected high AA pass rate on accessible page, got %.2f%%", passRate*100)
			}
		}

		// Verify violation details
		for _, violation := range result.Violations {
			if violation.Ratio == 0 {
				t.Error("Violation has zero contrast ratio")
			}
			if violation.Element == "" {
				t.Error("Violation missing element selector")
			}
		}
	}
}

// testKeyboardNavigation tests keyboard navigation testing
func testKeyboardNavigation(c *client.Client) func(*testing.T) {
	return func(t *testing.T) {
		result, err := c.TestKeyboard("", 10)
		if err != nil {
			t.Fatalf("Failed to test keyboard navigation: %v", err)
		}

		if result == nil {
			t.Fatal("Keyboard test result is nil")
		}

		// Verify result structure
		if result.TotalElements == 0 {
			t.Error("No interactive elements found")
		}

		t.Logf("Keyboard test: %d elements, %d focusable, %d not focusable, %d missing focus indicator, %d keyboard traps",
			result.TotalElements, result.Focusable, result.NotFocusable, result.MissingFocusIndicator, result.KeyboardTraps)

		// For accessible page, we expect high focusability rate
		if result.TotalElements > 0 {
			focusableRate := float64(result.Focusable) / float64(result.TotalElements)
			if focusableRate < 0.8 {
				t.Errorf("Expected high focusability rate on accessible page, got %.2f%%", focusableRate*100)
			}
		}

		// Verify tab order
		if len(result.TabOrder) == 0 {
			t.Error("Tab order is empty")
		}

		// Verify issue details
		for _, issue := range result.Issues {
			if issue.Type == "" {
				t.Error("Issue missing type")
			}
			if issue.Element == "" {
				t.Error("Issue missing element selector")
			}
		}
	}
}

// testZoomTesting tests zoom functionality testing
func testZoomTesting(c *client.Client) func(*testing.T) {
	return func(t *testing.T) {
		zoomLevels := []float64{1.0, 2.0, 4.0}
		result, err := c.TestZoom("", zoomLevels, 10)
		if err != nil {
			t.Fatalf("Failed to test zoom: %v", err)
		}

		if result == nil {
			t.Fatal("Zoom test result is nil")
		}

		// Verify we tested all zoom levels
		if len(result.ZoomLevels) != len(zoomLevels) {
			t.Errorf("Expected %d zoom levels, got %d", len(zoomLevels), len(result.ZoomLevels))
		}

		t.Logf("Zoom test: tested %d levels, found %d issues", len(result.ZoomLevels), len(result.Issues))

		// Verify zoom level details
		for _, zoomTest := range result.ZoomLevels {
			if zoomTest.ZoomLevel == 0 {
				t.Error("Zoom level is zero")
			}
			if zoomTest.ViewportWidth == 0 || zoomTest.ViewportHeight == 0 {
				t.Error("Viewport dimensions are zero")
			}

			// For accessible page at 200%, we expect no horizontal scroll
			if zoomTest.ZoomLevel == 2.0 && zoomTest.HasHorizontalScroll {
				t.Error("Expected no horizontal scroll at 200% zoom on accessible page")
			}
		}
	}
}

// testReflowTesting tests responsive reflow testing
func testReflowTesting(c *client.Client) func(*testing.T) {
	return func(t *testing.T) {
		widths := []int{320, 1280}
		result, err := c.TestReflow("", widths, 10)
		if err != nil {
			t.Fatalf("Failed to test reflow: %v", err)
		}

		if result == nil {
			t.Fatal("Reflow test result is nil")
		}

		// Verify we tested all widths
		if len(result.Breakpoints) != len(widths) {
			t.Errorf("Expected %d breakpoints, got %d", len(widths), len(result.Breakpoints))
		}

		t.Logf("Reflow test: tested %d breakpoints, found %d issues", len(result.Breakpoints), len(result.Issues))

		// Verify breakpoint details
		for _, breakpoint := range result.Breakpoints {
			if breakpoint.Width == 0 {
				t.Error("Breakpoint width is zero")
			}
			if breakpoint.Height == 0 {
				t.Error("Breakpoint height is zero")
			}

			// For accessible page at 320px, we expect no horizontal scroll
			if breakpoint.Width == 320 && breakpoint.HasHorizontalScroll {
				t.Error("Expected no horizontal scroll at 320px on accessible page")
			}

			// Verify responsive layout
			if !breakpoint.ResponsiveLayout {
				t.Errorf("Expected responsive layout at %dpx", breakpoint.Width)
			}
		}
	}
}

// testScreenshotEnhancements tests enhanced screenshot functionality
func testScreenshotEnhancements(c *client.Client) func(*testing.T) {
	return func(t *testing.T) {
		// Test basic screenshot
		err := c.TakeScreenshot("", "/tmp/test-screenshot.png", false, 5)
		if err != nil {
			t.Fatalf("Failed to take screenshot: %v", err)
		}

		// Verify file exists
		if _, err := os.Stat("/tmp/test-screenshot.png"); os.IsNotExist(err) {
			t.Error("Screenshot file was not created")
		}

		// Clean up
		os.Remove("/tmp/test-screenshot.png")

		t.Log("Screenshot functionality verified")
	}
}

// testLibraryInjection tests library injection via console_command
func testLibraryInjection(c *client.Client) func(*testing.T) {
	return func(t *testing.T) {
		// Test injecting jQuery
		params := map[string]string{
			"command":        "typeof jQuery",
			"inject_library": "jquery",
			"timeout":        "10",
		}

		resp, err := c.SendCommand("console-command", params)
		if err != nil {
			t.Fatalf("Failed to execute console command with library injection: %v", err)
		}

		if !resp.Success {
			t.Fatalf("Console command failed: %s", resp.Error)
		}

		// Verify jQuery was injected
		if resp.Data == nil {
			t.Error("Console command returned no data")
		}

		t.Log("Library injection functionality verified")
	}
}

// testAccessibilityTree tests accessibility tree retrieval
func testAccessibilityTree(c *client.Client) func(*testing.T) {
	return func(t *testing.T) {
		depth := 3
		result, err := c.GetAccessibilityTree("", &depth, 10)
		if err != nil {
			t.Fatalf("Failed to get accessibility tree: %v", err)
		}

		if result == nil {
			t.Fatal("Accessibility tree result is nil")
		}

		// Verify we got nodes
		if len(result.Nodes) == 0 {
			t.Error("Accessibility tree has no nodes")
		}

		t.Logf("Accessibility tree: %d nodes", len(result.Nodes))

		// Verify node structure
		foundRootNode := false
		for _, node := range result.Nodes {
			if node.NodeID == "" {
				t.Error("Node missing NodeID")
			}

			// Check for root node
			if node.Role != nil && node.Role.Value == "WebArea" {
				foundRootNode = true
			}
		}

		if !foundRootNode {
			t.Error("No root node found in accessibility tree")
		}
	}
}

// TestInaccessiblePage tests tools against a page with known accessibility issues
func TestInaccessiblePage(t *testing.T) {
	// Skip if not in integration test mode
	if os.Getenv("INTEGRATION_TESTS") != "true" {
		t.Skip("Skipping integration tests. Set INTEGRATION_TESTS=true to run.")
	}

	c := client.NewClient(daemonAddr)

	// Navigate to inaccessible test page
	err := c.Navigate("", testServerURL+"/test-inaccessible.html", false, 10)
	if err != nil {
		t.Fatalf("Failed to navigate to test page: %v", err)
	}

	time.Sleep(2 * time.Second)

	// Inject and run axe-core
	err = c.InjectAxeCore("", "4.8.0", 30)
	if err != nil {
		t.Fatalf("Failed to inject axe-core: %v", err)
	}

	runOnly := []string{"wcag2a", "wcag2aa"}
	result, err := c.RunAxeCore("", runOnly, nil, 30)
	if err != nil {
		t.Fatalf("Failed to run axe-core: %v", err)
	}

	// For inaccessible page, we expect violations
	if len(result.Violations) == 0 {
		t.Error("Expected violations on inaccessible page, got none")
	}

	t.Logf("Found %d violations on inaccessible page (expected)", len(result.Violations))

	// Test contrast checking - expect failures
	contrastResult, err := c.CheckContrast("", "body", 10)
	if err != nil {
		t.Fatalf("Failed to check contrast: %v", err)
	}

	if contrastResult.WCAGAAFail == 0 {
		t.Error("Expected contrast failures on inaccessible page, got none")
	}

	t.Logf("Found %d contrast failures on inaccessible page (expected)", contrastResult.WCAGAAFail)
}

// BenchmarkAxeCore benchmarks axe-core execution
func BenchmarkAxeCore(b *testing.B) {
	if os.Getenv("INTEGRATION_TESTS") != "true" {
		b.Skip("Skipping integration tests. Set INTEGRATION_TESTS=true to run.")
	}

	c := client.NewClient(daemonAddr)

	// Navigate once
	c.Navigate("", testServerURL+"/test-accessible.html", false, 10)
	time.Sleep(2 * time.Second)

	// Inject once
	c.InjectAxeCore("", "4.8.0", 30)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		runOnly := []string{"wcag2aa"}
		_, err := c.RunAxeCore("", runOnly, nil, 30)
		if err != nil {
			b.Fatalf("Failed to run axe-core: %v", err)
		}
	}
}

// Helper function to pretty print JSON
func prettyPrint(v interface{}) string {
	b, err := json.MarshalIndent(v, "", "  ")
	if err != nil {
		return fmt.Sprintf("%+v", v)
	}
	return string(b)
}

