package domain

import (
	"errors"
	"testing"
)

func TestVerifySpec_Validate(t *testing.T) {
	tests := []struct {
		name    string
		spec    VerifySpec
		wantErr error
	}{
		{
			name:    "valid spec with URL only",
			spec:    VerifySpec{URL: "https://example.com"},
			wantErr: nil,
		},
		{
			name: "valid spec with all fields",
			spec: VerifySpec{
				URL:         "https://example.com/page",
				Viewports:   []string{"1920x1080", "375x667"},
				WaitFor:     "#main",
				WaitTimeout: 5000,
				FullPage:    true,
				Video:       true,
				CallbackURL: "https://webhook.example.com/notify",
			},
			wantErr: nil,
		},
		{
			name:    "empty URL",
			spec:    VerifySpec{},
			wantErr: ErrVerifyURLRequired,
		},
		{
			name:    "invalid URL scheme",
			spec:    VerifySpec{URL: "ftp://example.com"},
			wantErr: nil, // Validate will fail but not return ErrVerifyURLRequired
		},
		{
			name:    "invalid callback URL scheme",
			spec:    VerifySpec{URL: "https://example.com", CallbackURL: "ftp://webhook.com"},
			wantErr: nil, // Validate will fail but not return ErrVerifyURLRequired
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := tt.spec.Validate()
			if tt.wantErr != nil {
				if !errors.Is(err, tt.wantErr) {
					t.Errorf("Validate() error = %v, want %v", err, tt.wantErr)
				}
			} else if tt.name == "invalid URL scheme" || tt.name == "invalid callback URL scheme" {
				// These should fail with a different error
				if err == nil {
					t.Errorf("Validate() expected error for %s", tt.name)
				}
			} else if err != nil {
				t.Errorf("Validate() unexpected error = %v", err)
			}
		})
	}
}

func TestVerifySpec_WithDefaults(t *testing.T) {
	t.Run("applies defaults to empty spec", func(t *testing.T) {
		spec := &VerifySpec{URL: "https://example.com"}
		result := spec.WithDefaults()

		if len(result.Viewports) != 3 {
			t.Errorf("expected 3 default viewports, got %d", len(result.Viewports))
		}
		if result.Viewports[0] != "1920x1080" {
			t.Errorf("expected first viewport '1920x1080', got %q", result.Viewports[0])
		}
		if result.WaitFor != "body" {
			t.Errorf("expected WaitFor 'body', got %q", result.WaitFor)
		}
		if result.WaitTimeout != 10000 {
			t.Errorf("expected WaitTimeout 10000, got %d", result.WaitTimeout)
		}
	})

	t.Run("preserves existing values", func(t *testing.T) {
		spec := &VerifySpec{
			URL:         "https://example.com",
			Viewports:   []string{"800x600"},
			WaitFor:     "#app",
			WaitTimeout: 5000,
		}
		result := spec.WithDefaults()

		if len(result.Viewports) != 1 || result.Viewports[0] != "800x600" {
			t.Errorf("expected preserved viewports, got %v", result.Viewports)
		}
		if result.WaitFor != "#app" {
			t.Errorf("expected preserved WaitFor, got %q", result.WaitFor)
		}
		if result.WaitTimeout != 5000 {
			t.Errorf("expected preserved WaitTimeout, got %d", result.WaitTimeout)
		}
	})

	t.Run("does not modify original", func(t *testing.T) {
		spec := &VerifySpec{URL: "https://example.com"}
		_ = spec.WithDefaults()

		if len(spec.Viewports) != 0 {
			t.Error("original spec should not be modified")
		}
	})
}

func TestVerifyResult_ToWorkResult(t *testing.T) {
	t.Run("success with screenshots", func(t *testing.T) {
		result := &VerifyResult{
			Success: true,
			Screenshots: map[string]string{
				"1920x1080": "/captures/task-1/1920_1080.png",
				"375x667":   "/captures/task-1/375_667.png",
			},
			DurationMs: 1500,
		}

		wr := result.ToWorkResult()

		if wr.Output != "" {
			t.Errorf("expected empty output on success, got %q", wr.Output)
		}
		if wr.Artifacts["screenshot_1920x1080"] != "/captures/task-1/1920_1080.png" {
			t.Errorf("screenshot_1920x1080 = %q", wr.Artifacts["screenshot_1920x1080"])
		}
		if wr.Artifacts["screenshot_375x667"] != "/captures/task-1/375_667.png" {
			t.Errorf("screenshot_375x667 = %q", wr.Artifacts["screenshot_375x667"])
		}
		if wr.Artifacts["duration_ms"] != "1500" {
			t.Errorf("duration_ms = %q", wr.Artifacts["duration_ms"])
		}
	})

	t.Run("success with video", func(t *testing.T) {
		result := &VerifyResult{
			Success:     true,
			Screenshots: map[string]string{"1920x1080": "/captures/task-1/1920_1080.png"},
			Video:       "/captures/task-1/recording.webm",
			DurationMs:  2000,
		}

		wr := result.ToWorkResult()

		if wr.Artifacts["video"] != "/captures/task-1/recording.webm" {
			t.Errorf("video = %q", wr.Artifacts["video"])
		}
	})

	t.Run("failure uses error as output", func(t *testing.T) {
		result := &VerifyResult{
			Success: false,
			Error:   "capture failed: timeout",
		}

		wr := result.ToWorkResult()

		if wr.Output != "capture failed: timeout" {
			t.Errorf("Output = %q, want error message", wr.Output)
		}
	})

	t.Run("nil receiver returns empty result", func(t *testing.T) {
		var result *VerifyResult
		wr := result.ToWorkResult()

		if wr.Output != "" {
			t.Errorf("Output = %q, want empty", wr.Output)
		}
		if wr.Artifacts != nil {
			t.Errorf("Artifacts = %v, want nil", wr.Artifacts)
		}
	})

	t.Run("evaluation results included", func(t *testing.T) {
		result := &VerifyResult{
			Success:    true,
			Evaluation: "Page renders correctly with all elements visible",
			Score:      85,
			Passed:     true,
			DurationMs: 1000,
		}

		wr := result.ToWorkResult()

		if wr.Artifacts["evaluation"] != "Page renders correctly with all elements visible" {
			t.Errorf("evaluation = %q", wr.Artifacts["evaluation"])
		}
		if wr.Artifacts["score"] != "85" {
			t.Errorf("score = %q", wr.Artifacts["score"])
		}
		if wr.Artifacts["passed"] != "true" {
			t.Errorf("passed = %q", wr.Artifacts["passed"])
		}
	})
}

func TestVerifyResult_ToBuildResult(t *testing.T) {
	t.Run("success conversion", func(t *testing.T) {
		result := &VerifyResult{
			Success: true,
			Screenshots: map[string]string{
				"1920x1080": "/captures/task-1/1920_1080.png",
			},
			Video:      "/captures/task-1/recording.webm",
			DurationMs: 1500,
		}

		br := result.ToBuildResult()

		if !br.Success {
			t.Error("expected success = true")
		}
		if br.DurationMs != 1500 {
			t.Errorf("DurationMs = %d, want 1500", br.DurationMs)
		}
		if br.Artifacts["screenshot_1920x1080"] != "/captures/task-1/1920_1080.png" {
			t.Errorf("screenshot artifact missing")
		}
		if br.Artifacts["video"] != "/captures/task-1/recording.webm" {
			t.Errorf("video artifact missing")
		}
	})

	t.Run("failure conversion", func(t *testing.T) {
		result := &VerifyResult{
			Success:    false,
			Error:      "capture failed",
			DurationMs: 500,
		}

		br := result.ToBuildResult()

		if br.Success {
			t.Error("expected success = false")
		}
		if br.Error != "capture failed" {
			t.Errorf("Error = %q", br.Error)
		}
	})

	t.Run("nil receiver returns empty", func(t *testing.T) {
		var result *VerifyResult
		br := result.ToBuildResult()

		if br.Success {
			t.Error("expected success = false for nil")
		}
	})
}

func TestDefaultViewports(t *testing.T) {
	viewports := DefaultViewports()

	if len(viewports) != 3 {
		t.Fatalf("expected 3 viewports, got %d", len(viewports))
	}

	expected := []string{"1920x1080", "768x1024", "375x667"}
	for i, vp := range expected {
		if viewports[i] != vp {
			t.Errorf("viewport[%d] = %q, want %q", i, viewports[i], vp)
		}
	}
}
