// Package probe implements the probe-ingest HTTP endpoint and the Redis
// storage layer for Pangolin's node-health probing subsystem.
//
// Schema contract (frozen after task 15A):
//
//   POST /probe/report  – ingest.go  – consumed by 15B (probe client)
//                                       and 15C (third-party dial-test)
//
// 15D (determination logic) reads from Redis via Store, but does not live here.
// This package intentionally has no determination logic, no gRPC, and no alerts.
package probe

// ReportRequest is the JSON body for POST /probe/report.
// This schema is frozen; 15B and 15C must conform.
type ReportRequest struct {
	// ProbeID identifies the probe agent submitting this report.
	// Must match the X-Probe-Id request header.
	ProbeID string `json:"probeId"`

	// Vantage describes the network vantage point of this probe agent.
	Vantage VantagePoint `json:"vantage"`

	// Reports contains one result entry per tested node.
	// A single request may carry results for multiple nodes.
	Reports []NodeReport `json:"reports"`
}

// VantagePoint describes the network vantage point of a probe agent.
type VantagePoint struct {
	// ISP is the Internet Service Provider name, e.g. "China Telecom".
	ISP string `json:"isp"`

	// Region is the geographic region or province, e.g. "Guangdong".
	Region string `json:"region"`

	// Country is the ISO 3166-1 alpha-2 country code, e.g. "CN".
	Country string `json:"country"`
}

// NodeReport holds the probe results for a single target node.
type NodeReport struct {
	// NodeID is the target node identifier (matches nodes.id in the DB).
	NodeID string `json:"nodeId"`

	// Ts is the Unix timestamp (seconds) when the probe was conducted.
	Ts int64 `json:"ts"`

	// L1 is the Layer-1 (TCP connectivity + RTT) result.
	L1 L1Result `json:"l1"`

	// L2 is the Layer-2 (TLS handshake + ALPN negotiation) result.
	// May be absent if L1 failed.
	L2 *L2Result `json:"l2,omitempty"`

	// L3 is the Layer-3 (application-protocol) result.
	// Optional: third-party dial-tests (15C) only populate L1/L2.
	L3 *L3Result `json:"l3,omitempty"`
}

// L1Result captures TCP-level reachability.
type L1Result struct {
	// OK indicates whether a TCP connection was successfully established.
	OK bool `json:"ok"`

	// RttMs is the round-trip time in milliseconds; 0 if connection failed.
	RttMs int `json:"rttMs"`
}

// L2Result captures TLS-level reachability.
type L2Result struct {
	// OK indicates whether the TLS handshake succeeded.
	OK bool `json:"ok"`

	// ALPN is the negotiated ALPN protocol identifier, e.g. "h3", "h2", or "".
	ALPN string `json:"alpn"`

	// Err is a short error description when OK is false; empty on success.
	Err string `json:"err,omitempty"`
}

// L3Result captures application-protocol-level reachability.
// Only first-party probe agents (15B) populate this; third-party (15C) omit it.
type L3Result struct {
	// OK indicates whether the application-level exchange succeeded.
	OK bool `json:"ok"`

	// Err is a short error description when OK is false; empty on success.
	Err string `json:"err,omitempty"`
}

// ProbeSnapshot is the stored form of a single probe result for one
// (node, vantage) pair, persisted as JSON in Redis.
type ProbeSnapshot struct {
	// ProbeID is the probe agent that produced this snapshot.
	ProbeID string `json:"probeId"`

	// Vantage is the vantage point from which the probe was conducted.
	Vantage VantagePoint `json:"vantage"`

	// Report is the original NodeReport from the probe agent.
	Report NodeReport `json:"report"`

	// ReceivedAt is the Unix timestamp (seconds) when this report was ingested.
	ReceivedAt int64 `json:"receivedAt"`
}
