//go:build e2e

package testkit

import (
	"context"
	"os"
	"strconv"
	"strings"
	"testing"
	"time"
)

// Canonical defaults for API scenario E2E. See e2e/docs/scenario-config.md.
const (
	// DefaultAllChannelSlug is the workspace default broadcast channel name.
	DefaultAllChannelSlug = "all"

	// DefaultMessageHistoryLimit is the page size for ListChannelMessages in assertions.
	DefaultMessageHistoryLimit = 50

	// DefaultEmbeddedRegisterPassword is used when embedded profile registers fresh users.
	DefaultEmbeddedRegisterPassword = "super-secret-password"

	// DefaultEmbeddedUserDisplayPrefix is prepended to registered user display names.
	DefaultEmbeddedUserDisplayPrefix = "e2e"

	// DefaultEmailDomain is used when embedded profile synthesizes test user emails.
	DefaultEmailDomain = "example.com"

	// DefaultHTTPStatusOK is the expected success status for JSON API calls in scenarios.
	DefaultHTTPStatusOK = 200

	// DefaultLocalServerHost is the bind host for embedded agentteam-e2e-server.
	DefaultLocalServerHost = "127.0.0.1"
)

const (
	defaultAPITimeout              = 30 * time.Second
	defaultPeerFlowTimeout         = 60 * time.Second
	defaultEmbeddedServerReady     = 180 * time.Second
	defaultReadyProbeHTTPTimeout   = 2 * time.Second
	defaultReadyProbeInterval      = 300 * time.Millisecond
	defaultMobileVerifyPollTimeout = 10 * time.Second
	defaultMobileVerifyHTTPTimeout = 2 * time.Second
	defaultMobileVerifyPollEvery   = 200 * time.Millisecond
)

// AllChannelSlug returns the slug used to resolve the default team channel.
func AllChannelSlug() string {
	return stringFromEnv("AGENTTEAM_E2E_ALL_CHANNEL_SLUG", DefaultAllChannelSlug)
}

// MessageHistoryLimit returns how many messages to fetch when asserting delivery.
func MessageHistoryLimit() int {
	return intFromEnv("AGENTTEAM_E2E_MESSAGE_LIST_LIMIT", DefaultMessageHistoryLimit)
}

// EmbeddedRegisterPassword returns the password for embedded Register API calls.
func EmbeddedRegisterPassword() string {
	return stringFromEnv("AGENTTEAM_E2E_REGISTER_PASSWORD", DefaultEmbeddedRegisterPassword)
}

// APITimeout bounds a single scenario API step (list/create/send).
func APITimeout() time.Duration {
	return durationFromEnv("AGENTTEAM_E2E_API_TIMEOUT", defaultAPITimeout)
}

// PeerFlowTimeout bounds invite/register/mobile-verify peer provisioning.
func PeerFlowTimeout() time.Duration {
	return durationFromEnv("AGENTTEAM_E2E_PEER_FLOW_TIMEOUT", defaultPeerFlowTimeout)
}

// EmbeddedServerReadyTimeout bounds wait for agentteam-e2e-server /readyz during startup.
func EmbeddedServerReadyTimeout() time.Duration {
	return durationFromEnv("AGENTTEAM_E2E_SERVER_READY_TIMEOUT", defaultEmbeddedServerReady)
}

// ReadyProbeHTTPTimeout is the per-request timeout when polling /readyz.
func ReadyProbeHTTPTimeout() time.Duration {
	return durationFromEnv("AGENTTEAM_E2E_READY_PROBE_HTTP_TIMEOUT", defaultReadyProbeHTTPTimeout)
}

// ReadyProbeInterval is the poll interval when waiting for /readyz.
func ReadyProbeInterval() time.Duration {
	return durationFromEnv("AGENTTEAM_E2E_READY_PROBE_INTERVAL", defaultReadyProbeInterval)
}

// MobileVerificationPollTimeout bounds polling /internal/e2e/mobile-verification/latest.
func MobileVerificationPollTimeout() time.Duration {
	return durationFromEnv("AGENTTEAM_E2E_MOBILE_VERIFY_POLL_TIMEOUT", defaultMobileVerifyPollTimeout)
}

// MobileVerificationHTTPTimeout is the per-request timeout for mobile verification polling.
func MobileVerificationHTTPTimeout() time.Duration {
	return durationFromEnv("AGENTTEAM_E2E_MOBILE_VERIFY_HTTP_TIMEOUT", defaultMobileVerifyHTTPTimeout)
}

// MobileVerificationPollInterval is the delay between mobile verification poll attempts.
func MobileVerificationPollInterval() time.Duration {
	return durationFromEnv("AGENTTEAM_E2E_MOBILE_VERIFY_POLL_INTERVAL", defaultMobileVerifyPollEvery)
}

// APIContext returns a context bounded by APITimeout for scenario API calls.
func APIContext(t *testing.T) (context.Context, context.CancelFunc) {
	t.Helper()
	return context.WithTimeout(context.Background(), APITimeout())
}

// PeerFlowContext returns a context bounded by PeerFlowTimeout for multi-user setup.
func PeerFlowContext(t *testing.T) (context.Context, context.CancelFunc) {
	t.Helper()
	return context.WithTimeout(context.Background(), PeerFlowTimeout())
}

func stringFromEnv(name, fallback string) string {
	if value := strings.TrimSpace(os.Getenv(name)); value != "" {
		return value
	}
	return fallback
}

func intFromEnv(name string, fallback int) int {
	raw := strings.TrimSpace(os.Getenv(name))
	if raw == "" {
		return fallback
	}
	parsed, err := strconv.Atoi(raw)
	if err != nil || parsed <= 0 {
		return fallback
	}
	return parsed
}

func durationFromEnv(name string, fallback time.Duration) time.Duration {
	raw := strings.TrimSpace(os.Getenv(name))
	if raw == "" {
		return fallback
	}
	parsed, err := time.ParseDuration(raw)
	if err != nil || parsed <= 0 {
		return fallback
	}
	return parsed
}
