package service

import (
	edgenode "iop/apps/edge/internal/node"
	"iop/packages/go/config"
	iop "iop/proto/gen/iop"
)

// NodeSnapshot is a surface-neutral view of a registered node, suitable for
// CLI, HTTP, or other transports. Label is the short display label (node0, node1).
// AgentKind and LifecycleState carry the registry entry's generic node
// classification and lifecycle.
type NodeSnapshot struct {
	NodeID            string
	Alias             string
	Label             string
	AgentKind         string
	LifecycleState    string
	Config            *iop.NodeConfigPayload
	ProviderSnapshots []*iop.ProviderSnapshot
}

// ListNodeSnapshots returns surface-neutral node descriptors derived from the
// current registry contents.
func (s *Service) ListNodeSnapshots() []NodeSnapshot {
	entries := s.registry.All()
	store, _ := s.runtimeConfigSnapshot()
	out := make([]NodeSnapshot, 0, len(entries))
	for _, entry := range entries {
		snap := NodeSnapshot{
			NodeID:         entry.NodeID,
			Alias:          entry.Alias,
			Label:          nodeLabel(entry),
			AgentKind:      entry.AgentKind,
			LifecycleState: entry.LifecycleState,
		}
		var rec *edgenode.NodeRecord
		if store != nil {
			if r, ok := store.FindByID(entry.NodeID); ok {
				rec = r
				if payload, err := edgenode.BuildConfigPayload(r); err == nil {
					snap.Config = payload
				}
			}
		}
		if rec != nil {
			if s.queue != nil {
				snap.ProviderSnapshots = s.queue.getSnapshotForNode(entry.NodeID, rec)
			} else if len(rec.Providers) > 0 {
				snap.ProviderSnapshots = staticProviderCatalogSnapshots(rec)
			}
		}
		out = append(out, snap)
	}
	return out
}

// NodeEntrySnapshot converts a registry entry into the surface-neutral DTO.
func NodeEntrySnapshot(entry *edgenode.NodeEntry) NodeSnapshot {
	if entry == nil {
		return NodeSnapshot{}
	}
	return NodeSnapshot{
		NodeID:         entry.NodeID,
		Alias:          entry.Alias,
		Label:          nodeLabel(entry),
		AgentKind:      entry.AgentKind,
		LifecycleState: entry.LifecycleState,
	}
}

// staticProviderCatalogSnapshots builds catalog-based ProviderSnapshots with
// zero inflight/queued for nodes whose config has a providers[] catalog but
// whose service has no queue (e.g. queue disabled at startup).
func staticProviderCatalogSnapshots(rec *edgenode.NodeRecord) []*iop.ProviderSnapshot {
	snaps := make([]*iop.ProviderSnapshot, 0, len(rec.Providers))
	for _, prov := range rec.Providers {
		if prov.ID == "" {
			continue
		}
		servedModels := make([]string, len(prov.Models))
		copy(servedModels, prov.Models)
		lifecycleCaps := make([]string, len(prov.LifecycleCapabilities))
		copy(lifecycleCaps, prov.LifecycleCapabilities)

		if !config.ProviderEnabled(prov) {
			snaps = append(snaps, &iop.ProviderSnapshot{
				Adapter:               prov.Adapter,
				Status:                "disabled",
				Capacity:              0,
				Id:                    prov.ID,
				Type:                  prov.Type,
				Category:              string(prov.Category),
				ServedModels:          servedModels,
				Health:                "disabled",
				LifecycleCapabilities: lifecycleCaps,
			})
			continue
		}

		snaps = append(snaps, &iop.ProviderSnapshot{
			Adapter:               prov.Adapter,
			Status:                "available",
			Capacity:              int32(prov.Capacity),
			Id:                    prov.ID,
			Type:                  prov.Type,
			Category:              string(prov.Category),
			ServedModels:          servedModels,
			Health:                prov.Health,
			LifecycleCapabilities: lifecycleCaps,
		})
	}
	return snaps
}

func (s *Service) ResolveNode(ref string) (*edgenode.NodeEntry, error) {
	return s.registry.Resolve(ref)
}

// ResolveNodeSnapshot returns a surface-neutral DTO for the resolved node.
func (s *Service) ResolveNodeSnapshot(ref string) (NodeSnapshot, error) {
	entry, err := s.ResolveNode(ref)
	if err != nil {
		return NodeSnapshot{}, err
	}
	return NodeEntrySnapshot(entry), nil
}

func (s *Service) GetCapabilities() []*iop.EdgeCapabilitySummary {
	var entries []*edgenode.NodeEntry
	if s.registry != nil {
		entries = s.registry.All()
	}
	if len(entries) == 0 {
		return nil
	}
	return []*iop.EdgeCapabilitySummary{
		{
			Kind:      "run",
			Available: true,
			Status:    "ready",
			Summary:   "Generic execution node available",
		},
	}
}

func (s *Service) GetDomainAgents() []*iop.EdgeDomainAgentSummary {
	return nil
}

// HealthStatusView is the Edge-owned status summary used by control commands
// such as health.check. It is derived from the live node registry and
// capability snapshot rather than a fixed simulation delay.
type HealthStatusView struct {
	Nodes        []NodeSnapshot
	Capabilities []*iop.EdgeCapabilitySummary
}

// HealthStatus returns a status summary derived from the current node registry
// and capability snapshot. It is the real Edge-owned boundary that backs the
// health.check control command.
func (s *Service) HealthStatus() HealthStatusView {
	return HealthStatusView{
		Nodes:        s.ListNodeSnapshots(),
		Capabilities: s.GetCapabilities(),
	}
}
