package health

import (
	"context"
	"fmt"
	"net/http"
	"time"
)

// DefaultRetries is the number of health check attempts before declaring failure.
const DefaultRetries = 3

// DefaultRetryInterval is the pause between health check retries.
const DefaultRetryInterval = 5 * time.Second

// DefaultTimeout is the HTTP timeout for a single health check attempt.
const DefaultTimeout = 10 * time.Second

// Checker performs HTTP health checks against a container endpoint.
type Checker struct {
	httpClient    *http.Client
	retries       int
	retryInterval time.Duration
}

// New creates a Checker with default settings.
func New() *Checker {
	return &Checker{
		httpClient: &http.Client{
			Timeout: DefaultTimeout,
		},
		retries:       DefaultRetries,
		retryInterval: DefaultRetryInterval,
	}
}

// Check performs an HTTP GET health check against the given URL.
// It retries up to the configured number of times, waiting retryInterval between attempts.
// Returns nil on the first successful (2xx) response, or the last error encountered.
func (c *Checker) Check(ctx context.Context, url string) error {
	var lastErr error

	for attempt := 0; attempt < c.retries; attempt++ {
		if attempt > 0 {
			select {
			case <-ctx.Done():
				return fmt.Errorf("health check cancelled: %w", ctx.Err())
			case <-time.After(c.retryInterval):
			}
		}

		lastErr = c.doCheck(ctx, url)
		if lastErr == nil {
			return nil
		}
	}

	return fmt.Errorf("health check failed after %d attempts: %w", c.retries, lastErr)
}

// doCheck performs a single HTTP GET health check.
func (c *Checker) doCheck(ctx context.Context, url string) error {
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
	if err != nil {
		return fmt.Errorf("create health check request: %w", err)
	}

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return fmt.Errorf("health check request to %s: %w", url, err)
	}
	defer resp.Body.Close()

	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return fmt.Errorf("health check %s returned status %d", url, resp.StatusCode)
	}

	return nil
}
