package domain

import (
	"errors"
	"fmt"
	"net/url"
	"strconv"
)

// Verify-related errors.
var (
	ErrVerifyURLRequired = errors.New("url is required for verify spec")
)

// VerifySpec defines what a verify task should accomplish.
type VerifySpec struct {
	// URL is the page to capture (required).
	URL string `json:"url"`

	// Viewports is a list of viewport sizes to capture.
	// Default: ["1920x1080", "768x1024", "375x667"]
	Viewports []string `json:"viewports,omitempty"`

	// WaitFor is a CSS selector to wait for before capturing.
	// Default: "body"
	WaitFor string `json:"wait_for,omitempty"`

	// WaitTimeout is the maximum time to wait for the selector in milliseconds.
	// Default: 10000
	WaitTimeout int `json:"wait_timeout,omitempty"`

	// FullPage captures the entire scrollable page if true.
	FullPage bool `json:"full_page,omitempty"`

	// Video records a video of the page load if true.
	Video bool `json:"video,omitempty"`

	// Evaluate enables AI evaluation of the captures (Week 3).
	Evaluate bool `json:"evaluate,omitempty"`

	// Prompt provides context for AI evaluation (Week 3).
	Prompt string `json:"prompt,omitempty"`

	// CallbackURL is the webhook URL for completion notification.
	CallbackURL string `json:"callback_url,omitempty"`
}

// DefaultViewports returns the default viewport sizes for captures.
func DefaultViewports() []string {
	return []string{"1920x1080", "768x1024", "375x667"}
}

// Validate checks that the VerifySpec has all required fields.
func (s *VerifySpec) Validate() error {
	if s.URL == "" {
		return ErrVerifyURLRequired
	}

	// Validate URL format
	u, err := url.Parse(s.URL)
	if err != nil {
		return fmt.Errorf("invalid url: %w", err)
	}
	if u.Scheme != "http" && u.Scheme != "https" {
		return fmt.Errorf("url scheme must be http or https, got %q", u.Scheme)
	}

	// Validate callback URL if provided
	if s.CallbackURL != "" {
		cu, err := url.Parse(s.CallbackURL)
		if err != nil {
			return fmt.Errorf("invalid callback_url: %w", err)
		}
		if cu.Scheme != "http" && cu.Scheme != "https" {
			return fmt.Errorf("callback_url scheme must be http or https, got %q", cu.Scheme)
		}
	}

	return nil
}

// WithDefaults returns a copy of the spec with default values applied.
func (s *VerifySpec) WithDefaults() *VerifySpec {
	spec := *s
	if len(spec.Viewports) == 0 {
		spec.Viewports = DefaultViewports()
	}
	if spec.WaitFor == "" {
		spec.WaitFor = "body"
	}
	if spec.WaitTimeout == 0 {
		spec.WaitTimeout = 10000
	}
	return &spec
}

// VerifyResult captures the outcome of a verify execution.
type VerifyResult struct {
	// Success indicates whether the capture completed successfully.
	Success bool `json:"success"`

	// Screenshots maps viewport size to screenshot file path.
	// Example: {"1920x1080": "/captures/task-id/1920_1080.png"}
	Screenshots map[string]string `json:"screenshots,omitempty"`

	// Video is the path to the recorded video if requested.
	Video string `json:"video,omitempty"`

	// Evaluation contains the AI evaluation result (Week 3).
	Evaluation string `json:"evaluation,omitempty"`

	// Score is the AI-assigned score 0-100 (Week 3).
	Score int `json:"score,omitempty"`

	// Passed indicates whether the AI evaluation passed (Week 3).
	Passed bool `json:"passed,omitempty"`

	// DurationMs is how long the capture took in milliseconds.
	DurationMs int64 `json:"duration_ms"`

	// Error contains the error message if capture failed.
	Error string `json:"error,omitempty"`
}

// ToWorkResult converts a VerifyResult to a WorkResult for queue compatibility.
// Screenshots are promoted to artifacts with viewport as key prefix.
func (r *VerifyResult) ToWorkResult() *WorkResult {
	if r == nil {
		return &WorkResult{}
	}

	wr := &WorkResult{}

	// Use error as output if failed, otherwise empty (captures are in artifacts)
	if !r.Success && r.Error != "" {
		wr.Output = r.Error
	}

	// Promote screenshots and metadata to artifacts
	if len(r.Screenshots) > 0 || r.Video != "" || r.DurationMs > 0 {
		wr.Artifacts = make(map[string]string)

		// Add screenshots
		for viewport, path := range r.Screenshots {
			wr.Artifacts["screenshot_"+viewport] = path
		}

		// Add video if present
		if r.Video != "" {
			wr.Artifacts["video"] = r.Video
		}

		// Add duration
		if r.DurationMs > 0 {
			wr.Artifacts["duration_ms"] = strconv.FormatInt(r.DurationMs, 10)
		}

		// Add evaluation results (Week 3)
		if r.Evaluation != "" {
			wr.Artifacts["evaluation"] = r.Evaluation
		}
		if r.Score > 0 {
			wr.Artifacts["score"] = strconv.Itoa(r.Score)
		}
		if r.Passed {
			wr.Artifacts["passed"] = "true"
		}
	}

	return wr
}

// ToBuildResult converts a VerifyResult to a BuildResult for executor compatibility.
// This allows the verify executor to return results through the work queue.
func (r *VerifyResult) ToBuildResult() *BuildResult {
	if r == nil {
		return &BuildResult{}
	}

	br := &BuildResult{
		Success:    r.Success,
		DurationMs: r.DurationMs,
		Error:      r.Error,
	}

	// Promote screenshots and video to artifacts
	if len(r.Screenshots) > 0 || r.Video != "" {
		br.Artifacts = make(map[string]string)
		for viewport, path := range r.Screenshots {
			br.Artifacts["screenshot_"+viewport] = path
		}
		if r.Video != "" {
			br.Artifacts["video"] = r.Video
		}
	}

	return br
}
