package worker

import (
	"context"
	"fmt"
	"testing"
	"time"

	"github.com/orchard9/rdev/internal/domain"
)

func TestVerifyExecutor_Execute_Success(t *testing.T) {
	cmdExec := newMockCommandExecutor()
	// Simulate capture.js JSON output
	cmdExec.output = []domain.OutputLine{
		{Stream: "stdout", Line: `{"screenshots":{"1920x1080":"/captures/task-1/1920_1080.png","375x667":"/captures/task-1/375_667.png"},"video":"/captures/task-1/recording.webm"}`, Timestamp: time.Now()},
	}

	exec := NewVerifyExecutor(cmdExec, nil, nil)

	task := &domain.WorkTask{
		ID:        "task-1",
		ProjectID: "project-1",
		Type:      domain.WorkTaskTypeVerify,
		Spec: map[string]any{
			"url":       "https://example.com",
			"viewports": []any{"1920x1080", "375x667"},
			"video":     true,
		},
	}

	result := exec.Execute(context.Background(), task)

	if !result.Success {
		t.Errorf("expected success, got error: %s", result.Error)
	}
	if result.DurationMs < 0 {
		t.Errorf("expected non-negative duration, got %d", result.DurationMs)
	}
	// Check artifacts were populated
	if result.Artifacts == nil {
		t.Fatal("expected artifacts to be populated")
	}
	if result.Artifacts["screenshot_1920x1080"] != "/captures/task-1/1920_1080.png" {
		t.Errorf("screenshot_1920x1080 = %q", result.Artifacts["screenshot_1920x1080"])
	}
	if result.Artifacts["video"] != "/captures/task-1/recording.webm" {
		t.Errorf("video = %q", result.Artifacts["video"])
	}
}

func TestVerifyExecutor_Execute_URLRequired(t *testing.T) {
	cmdExec := newMockCommandExecutor()
	exec := NewVerifyExecutor(cmdExec, nil, nil)

	task := &domain.WorkTask{
		ID:        "task-1",
		ProjectID: "project-1",
		Type:      domain.WorkTaskTypeVerify,
		Spec:      map[string]any{}, // Missing URL
	}

	result := exec.Execute(context.Background(), task)

	if result.Success {
		t.Error("expected failure for missing URL")
	}
	if result.Error == "" {
		t.Error("expected error message")
	}
}

func TestVerifyExecutor_Execute_InvalidURL(t *testing.T) {
	cmdExec := newMockCommandExecutor()
	exec := NewVerifyExecutor(cmdExec, nil, nil)

	task := &domain.WorkTask{
		ID:        "task-1",
		ProjectID: "project-1",
		Type:      domain.WorkTaskTypeVerify,
		Spec: map[string]any{
			"url": "ftp://invalid-scheme.com",
		},
	}

	result := exec.Execute(context.Background(), task)

	if result.Success {
		t.Error("expected failure for invalid URL scheme")
	}
}

func TestVerifyExecutor_Execute_CaptureFailure(t *testing.T) {
	cmdExec := newMockCommandExecutor()
	cmdExec.err = fmt.Errorf("kubectl exec failed: connection refused")

	exec := NewVerifyExecutor(cmdExec, nil, nil)

	task := &domain.WorkTask{
		ID:        "task-1",
		ProjectID: "project-1",
		Type:      domain.WorkTaskTypeVerify,
		Spec: map[string]any{
			"url": "https://example.com",
		},
	}

	result := exec.Execute(context.Background(), task)

	if result.Success {
		t.Error("expected failure on capture execution error")
	}
	if result.Error == "" {
		t.Error("expected error message")
	}
}

func TestVerifyExecutor_Execute_NonZeroExitCode(t *testing.T) {
	cmdExec := newMockCommandExecutor()
	cmdExec.result = &domain.CommandResult{
		ExitCode:   1,
		DurationMs: 100,
	}

	exec := NewVerifyExecutor(cmdExec, nil, nil)

	task := &domain.WorkTask{
		ID:        "task-1",
		ProjectID: "project-1",
		Type:      domain.WorkTaskTypeVerify,
		Spec: map[string]any{
			"url": "https://example.com",
		},
	}

	result := exec.Execute(context.Background(), task)

	if result.Success {
		t.Error("expected failure on non-zero exit code")
	}
}

func TestVerifyExecutor_Execute_InvalidManifestJSON(t *testing.T) {
	cmdExec := newMockCommandExecutor()
	cmdExec.output = []domain.OutputLine{
		{Stream: "stdout", Line: "not valid json", Timestamp: time.Now()},
	}

	exec := NewVerifyExecutor(cmdExec, nil, nil)

	task := &domain.WorkTask{
		ID:        "task-1",
		ProjectID: "project-1",
		Type:      domain.WorkTaskTypeVerify,
		Spec: map[string]any{
			"url": "https://example.com",
		},
	}

	result := exec.Execute(context.Background(), task)

	if result.Success {
		t.Error("expected failure on invalid JSON manifest")
	}
}

func TestVerifyExecutor_ParseSpec(t *testing.T) {
	exec := NewVerifyExecutor(nil, nil, nil)

	t.Run("valid spec with all fields", func(t *testing.T) {
		spec, err := exec.parseSpec(map[string]any{
			"url":          "https://example.com",
			"viewports":    []any{"1920x1080", "800x600"},
			"wait_for":     "#main",
			"wait_timeout": float64(5000),
			"full_page":    true,
			"video":        true,
			"evaluate":     true,
			"prompt":       "Check for hero section",
			"callback_url": "https://webhook.example.com/notify",
		})
		if err != nil {
			t.Fatalf("parseSpec() error = %v", err)
		}
		if spec.URL != "https://example.com" {
			t.Errorf("URL = %q", spec.URL)
		}
		if len(spec.Viewports) != 2 {
			t.Errorf("Viewports count = %d", len(spec.Viewports))
		}
		if spec.WaitFor != "#main" {
			t.Errorf("WaitFor = %q", spec.WaitFor)
		}
		if spec.WaitTimeout != 5000 {
			t.Errorf("WaitTimeout = %d", spec.WaitTimeout)
		}
		if !spec.FullPage {
			t.Error("expected FullPage = true")
		}
		if !spec.Video {
			t.Error("expected Video = true")
		}
		if !spec.Evaluate {
			t.Error("expected Evaluate = true")
		}
		if spec.Prompt != "Check for hero section" {
			t.Errorf("Prompt = %q", spec.Prompt)
		}
		if spec.CallbackURL != "https://webhook.example.com/notify" {
			t.Errorf("CallbackURL = %q", spec.CallbackURL)
		}
	})

	t.Run("minimal spec", func(t *testing.T) {
		spec, err := exec.parseSpec(map[string]any{
			"url": "https://example.com",
		})
		if err != nil {
			t.Fatalf("parseSpec() error = %v", err)
		}
		if spec.URL != "https://example.com" {
			t.Errorf("URL = %q", spec.URL)
		}
		// Other fields should be zero/empty
		if len(spec.Viewports) != 0 {
			t.Errorf("expected empty viewports, got %v", spec.Viewports)
		}
	})

	t.Run("missing URL", func(t *testing.T) {
		_, err := exec.parseSpec(map[string]any{
			"viewports": []any{"1920x1080"},
		})
		if err == nil {
			t.Error("expected error for missing URL")
		}
	})
}

func TestVerifyExecutor_BuildCaptureCommand(t *testing.T) {
	exec := NewVerifyExecutor(nil, nil, nil)

	spec := &domain.VerifySpec{
		URL:       "https://example.com/page",
		Viewports: []string{"1920x1080", "375x667"},
		WaitFor:   "#app",
		FullPage:  true,
		Video:     true,
	}

	args := exec.buildCaptureCommand(spec, "/captures/task-123")

	// Check command structure
	if args[0] != "node" {
		t.Errorf("expected 'node', got %q", args[0])
	}
	if args[1] != "/scripts/capture.js" {
		t.Errorf("expected '/scripts/capture.js', got %q", args[1])
	}

	// Check URL is included
	found := false
	for _, arg := range args {
		if arg == "--url=https://example.com/page" {
			found = true
			break
		}
	}
	if !found {
		t.Errorf("URL argument not found in %v", args)
	}

	// Check viewports
	found = false
	for _, arg := range args {
		if arg == "--viewports=1920x1080,375x667" {
			found = true
			break
		}
	}
	if !found {
		t.Errorf("viewports argument not found in %v", args)
	}

	// Check full-page flag
	found = false
	for _, arg := range args {
		if arg == "--full-page=true" {
			found = true
			break
		}
	}
	if !found {
		t.Errorf("full-page argument not found in %v", args)
	}

	// Check video flag
	found = false
	for _, arg := range args {
		if arg == "--video=true" {
			found = true
			break
		}
	}
	if !found {
		t.Errorf("video argument not found in %v", args)
	}
}

func TestVerifyExecutor_Config(t *testing.T) {
	t.Run("default config", func(t *testing.T) {
		exec := NewVerifyExecutor(nil, nil, nil)
		if exec.namespace != "rdev" {
			t.Errorf("namespace = %q, want 'rdev'", exec.namespace)
		}
		if exec.podName != "playwright-0" {
			t.Errorf("podName = %q, want 'playwright-0'", exec.podName)
		}
	})

	t.Run("custom config", func(t *testing.T) {
		exec := NewVerifyExecutor(nil, nil, &VerifyExecutorConfig{
			Namespace: "custom-ns",
			PodName:   "custom-pod-0",
		})
		if exec.namespace != "custom-ns" {
			t.Errorf("namespace = %q, want 'custom-ns'", exec.namespace)
		}
		if exec.podName != "custom-pod-0" {
			t.Errorf("podName = %q, want 'custom-pod-0'", exec.podName)
		}
	})
}
