package track1

import (
	"context"
	"os"
	"strings"
	"time"

	"github.com/explorer/backend/api/freshness"
)

func relaySnapshotStatus(relay map[string]interface{}) string {
	if relay == nil {
		return ""
	}
	if probe, ok := relay["url_probe"].(map[string]interface{}); ok {
		if okValue, exists := probe["ok"].(bool); exists && !okValue {
			return "down"
		}
		if body, ok := probe["body"].(map[string]interface{}); ok {
			if status, ok := body["status"].(string); ok {
				return strings.ToLower(strings.TrimSpace(status))
			}
		}
	}
	if _, ok := relay["file_snapshot_error"].(string); ok {
		return "down"
	}
	if snapshot, ok := relay["file_snapshot"].(map[string]interface{}); ok {
		if status, ok := snapshot["status"].(string); ok {
			return strings.ToLower(strings.TrimSpace(status))
		}
	}
	return ""
}

func relayNeedsAttention(relay map[string]interface{}) bool {
	status := relaySnapshotStatus(relay)
	switch status {
	case "degraded", "stale", "stopped", "down":
		return true
	default:
		return false
	}
}

// BuildBridgeStatusData builds the inner `data` object for bridge/status and SSE payloads.
func (s *Server) BuildBridgeStatusData(ctx context.Context) map[string]interface{} {
	rpc138 := strings.TrimSpace(os.Getenv("RPC_URL"))
	if rpc138 == "" {
		rpc138 = "http://localhost:8545"
	}

	var probes []RPCProbeResult
	p138 := ProbeEVMJSONRPC(ctx, "chain-138", "138", rpc138)
	probes = append(probes, p138)

	if eth := strings.TrimSpace(os.Getenv("ETH_MAINNET_RPC_URL")); eth != "" {
		probes = append(probes, ProbeEVMJSONRPC(ctx, "ethereum-mainnet", "1", eth))
	}

	for _, row := range ParseExtraRPCProbes() {
		name, u, ck := row[0], row[1], row[2]
		probes = append(probes, ProbeEVMJSONRPC(ctx, name, ck, u))
	}

	overall := "operational"
	if !p138.OK {
		overall = "degraded"
	} else {
		for _, p := range probes {
			if !p.OK {
				overall = "degraded"
				break
			}
		}
	}

	now := time.Now().UTC().Format(time.RFC3339)
	chains := map[string]interface{}{
		"138": map[string]interface{}{
			"name":         "Defi Oracle Meta Mainnet",
			"status":       chainStatusFromProbe(p138),
			"last_sync":    now,
			"latency_ms":   p138.LatencyMs,
			"head_age_sec": p138.HeadAgeSeconds,
			"block_number": p138.BlockNumberDec,
			"endpoint":     p138.Endpoint,
			"probe_error":  p138.Error,
		},
	}

	for _, p := range probes {
		if p.ChainKey != "1" && p.Name != "ethereum-mainnet" {
			continue
		}
		chains["1"] = map[string]interface{}{
			"name":         "Ethereum Mainnet",
			"status":       chainStatusFromProbe(p),
			"last_sync":    now,
			"latency_ms":   p.LatencyMs,
			"head_age_sec": p.HeadAgeSeconds,
			"block_number": p.BlockNumberDec,
			"endpoint":     p.Endpoint,
			"probe_error":  p.Error,
		}
		break
	}

	probeJSON := make([]map[string]interface{}, 0, len(probes))
	for _, p := range probes {
		probeJSON = append(probeJSON, map[string]interface{}{
			"name":           p.Name,
			"chainKey":       p.ChainKey,
			"endpoint":       p.Endpoint,
			"ok":             p.OK,
			"latencyMs":      p.LatencyMs,
			"blockNumber":    p.BlockNumber,
			"blockNumberDec": p.BlockNumberDec,
			"headAgeSeconds": p.HeadAgeSeconds,
			"error":          p.Error,
		})
	}

	data := map[string]interface{}{
		"status":     overall,
		"chains":     chains,
		"rpc_probe":  probeJSON,
		"checked_at": now,
	}
	if ov := readOptionalVerifyJSON(); ov != nil {
		data["operator_verify"] = ov
	}
	if s.freshnessLoader != nil {
		if snapshot, completeness, sampling, diagnostics, err := s.freshnessLoader(ctx); err == nil && snapshot != nil {
			subsystems := map[string]interface{}{
				"rpc_head": map[string]interface{}{
					"status":       chainStatusFromProbe(p138),
					"updated_at":   valueOrNil(snapshot.ChainHead.Timestamp),
					"age_seconds":  valueOrNil(snapshot.ChainHead.AgeSeconds),
					"source":       snapshot.ChainHead.Source,
					"confidence":   snapshot.ChainHead.Confidence,
					"provenance":   snapshot.ChainHead.Provenance,
					"completeness": snapshot.ChainHead.Completeness,
				},
				"tx_index": map[string]interface{}{
					"status":       completenessStatus(completeness.TransactionsFeed),
					"updated_at":   valueOrNil(snapshot.LatestIndexedTransaction.Timestamp),
					"age_seconds":  valueOrNil(snapshot.LatestIndexedTransaction.AgeSeconds),
					"source":       snapshot.LatestIndexedTransaction.Source,
					"confidence":   snapshot.LatestIndexedTransaction.Confidence,
					"provenance":   snapshot.LatestIndexedTransaction.Provenance,
					"completeness": completeness.TransactionsFeed,
				},
				"stats_summary": map[string]interface{}{
					"status":       completenessStatus(completeness.BlocksFeed),
					"updated_at":   valueOrNil(sampling.StatsGeneratedAt),
					"age_seconds":  ageSinceRFC3339(sampling.StatsGeneratedAt),
					"source":       freshness.SourceReported,
					"confidence":   freshness.ConfidenceMedium,
					"provenance":   freshness.ProvenanceComposite,
					"completeness": completeness.BlocksFeed,
				},
			}
			if len(sampling.Issues) > 0 {
				subsystems["freshness_queries"] = map[string]interface{}{
					"status":       "degraded",
					"updated_at":   valueOrNil(sampling.StatsGeneratedAt),
					"age_seconds":  ageSinceRFC3339(sampling.StatsGeneratedAt),
					"source":       freshness.SourceDerived,
					"confidence":   freshness.ConfidenceMedium,
					"provenance":   freshness.ProvenanceComposite,
					"completeness": freshness.CompletenessPartial,
					"issues":       sampling.Issues,
				}
			}
			modeKind := "live"
			modeReason := any(nil)
			modeScope := any(nil)
			if relays, ok := data["ccip_relays"].(map[string]interface{}); ok && len(relays) > 0 {
				modeKind = "snapshot"
				modeReason = "live_homepage_stream_not_attached"
				modeScope = "relay_monitoring_homepage_card_only"
				subsystems["bridge_relay_monitoring"] = map[string]interface{}{
					"status":       overall,
					"updated_at":   now,
					"age_seconds":  int64(0),
					"source":       freshness.SourceReported,
					"confidence":   freshness.ConfidenceHigh,
					"provenance":   freshness.ProvenanceMissionFeed,
					"completeness": freshness.CompletenessComplete,
				}
			}
			data["freshness"] = snapshot
			data["subsystems"] = subsystems
			data["sampling"] = sampling
			if diagnostics != nil {
				data["diagnostics"] = diagnostics
			}
			data["mode"] = map[string]interface{}{
				"kind":        modeKind,
				"updated_at":  now,
				"age_seconds": int64(0),
				"reason":      modeReason,
				"scope":       modeScope,
				"source":      freshness.SourceReported,
				"confidence":  freshness.ConfidenceHigh,
				"provenance":  freshness.ProvenanceMissionFeed,
			}
		}
	}
	if relays := FetchCCIPRelayHealths(ctx); relays != nil {
		data["ccip_relays"] = relays
		if ccip := primaryRelayHealth(relays); ccip != nil {
			data["ccip_relay"] = ccip
		}
		for _, value := range relays {
			relay, ok := value.(map[string]interface{})
			if ok && relayNeedsAttention(relay) {
				data["status"] = "degraded"
				break
			}
		}
	}
	if mode, ok := data["mode"].(map[string]interface{}); ok {
		if relays, ok := data["ccip_relays"].(map[string]interface{}); ok && len(relays) > 0 {
			mode["kind"] = "snapshot"
			mode["reason"] = "live_homepage_stream_not_attached"
			mode["scope"] = "relay_monitoring_homepage_card_only"
			if subsystems, ok := data["subsystems"].(map[string]interface{}); ok {
				subsystems["bridge_relay_monitoring"] = map[string]interface{}{
					"status":       data["status"],
					"updated_at":   now,
					"age_seconds":  int64(0),
					"source":       freshness.SourceReported,
					"confidence":   freshness.ConfidenceHigh,
					"provenance":   freshness.ProvenanceMissionFeed,
					"completeness": freshness.CompletenessComplete,
				}
			}
		}
	}
	return data
}

func valueOrNil[T any](value *T) any {
	if value == nil {
		return nil
	}
	return *value
}

func ageSinceRFC3339(value *string) any {
	if value == nil || *value == "" {
		return nil
	}
	parsed, err := time.Parse(time.RFC3339, *value)
	if err != nil {
		return nil
	}
	age := int64(time.Since(parsed).Seconds())
	if age < 0 {
		age = 0
	}
	return age
}

func completenessStatus(value freshness.Completeness) string {
	switch value {
	case freshness.CompletenessComplete:
		return "operational"
	case freshness.CompletenessPartial:
		return "partial"
	case freshness.CompletenessStale:
		return "stale"
	default:
		return "unavailable"
	}
}
