syntax = "proto3";
package peerman;

// ── Peer Service ──

service PeerService {
  rpc ListPeers(ListPeersRequest) returns (ListPeersResponse);
  rpc GetPeer(GetPeerRequest) returns (Peer);
  rpc CreatePeer(CreatePeerRequest) returns (Peer);
  rpc UpdatePeer(UpdatePeerRequest) returns (Peer);
  rpc DeletePeer(DeletePeerRequest) returns (DeletePeerResponse);
  rpc TogglePeer(TogglePeerRequest) returns (Peer);
  rpc GenerateKeypair(GenerateKeypairRequest) returns (GenerateKeypairResponse);
  rpc GetWireGuardConfig(GetConfigRequest) returns (ConfigResponse);
  rpc GetBirdConfig(GetConfigRequest) returns (ConfigResponse);
  rpc ExportAllWireGuard(ExportAllRequest) returns (ConfigResponse);
  rpc ExportAllBird(ExportAllRequest) returns (ConfigResponse);
  rpc RestartWireGuard(RestartWireGuardRequest) returns (RestartWireGuardResponse);
}

// ── Settings Service ──

service SettingsService {
  rpc GetSettings(GetSettingsRequest) returns (Settings);
  rpc SaveSettings(SaveSettingsRequest) returns (Settings);
}

// ── Enums ──

enum SessionProtocol {
  SESSION_IPV4 = 0;
  SESSION_IPV6 = 1;
  SESSION_BOTH = 2;
}

// ── Core Messages ──

message Peer {
  string id = 1;
  string name = 2;
  string description = 3;
  int64 asn = 4;
  int64 local_asn = 5;
  // WireGuard
  string wg_private_key = 6;
  string wg_public_key = 7;
  string wg_remote_address = 8;
  uint32 wg_remote_port = 9;
  uint32 wg_listen_port = 10;
  string wg_interface_name = 11;
  // Tunnel addressing
  string ipv4_tunnel_local = 12;
  string ipv4_tunnel_remote = 13;
  string ipv6_tunnel_local = 14;
  string ipv6_tunnel_remote = 15;
  // BGP session
  bool multiprotocol = 16;
  bool extended_nexthop = 17;
  SessionProtocol sessions = 18;
  bool passive = 19;
  int32 import_max_prefix = 20;
  int32 export_max_prefix = 21;
  // Metadata
  bool enabled = 22;
  string created_at = 23;
  string updated_at = 24;
  // Cluster
  string origin_node_id = 25;
}

message Settings {
  int64 local_asn = 1;
  string bird_template_name = 2;
  string bird_router_id = 3;
  uint32 wg_default_listen_port = 4;
  string dn42_ipv4_prefix = 5;
  string dn42_ipv6_prefix = 6;
  string wg_table = 7;
  // WireGuard advanced
  uint32 wg_mtu = 8;
  uint32 wg_fwmark = 9;
  string wg_post_up = 10;
  string wg_post_down = 11;
  // ROA/RPKI
  string roa_mode = 12;
  string roa_static_v4_url = 13;
  string roa_static_v6_url = 14;
  string roa_rtr_address = 15;
  uint32 roa_rtr_port = 16;
  // BIRD filter
  uint32 bird_import_limit = 17;
  string bird_export_filter = 18;
  string bird_import_filter = 19;
  // Community filters
  bool enable_community_filters = 20;
  // BFD
  bool enable_bfd = 21;
  uint32 bfd_interval_ms = 22;
  uint32 bfd_multiplier = 23;
  // Cluster IPv6
  string cluster_tunnel_ipv6_range = 24;
  // BGP Confederation
  bool enable_confederation = 25;
  int64 confederation_local_asn = 26;
}

// ── Peer Service Requests / Responses ──

message ListPeersRequest {}

message ListPeersResponse {
  repeated Peer peers = 1;
}

message GetPeerRequest {
  string id = 1;
}

message CreatePeerRequest {
  string name = 1;
  string description = 2;
  int64 asn = 3;
  int64 local_asn = 4;
  string wg_private_key = 5;
  string wg_public_key = 6;
  string wg_remote_address = 7;
  uint32 wg_remote_port = 8;
  uint32 wg_listen_port = 9;
  string wg_interface_name = 10;
  string ipv4_tunnel_local = 11;
  string ipv4_tunnel_remote = 12;
  string ipv6_tunnel_local = 13;
  string ipv6_tunnel_remote = 14;
  bool multiprotocol = 15;
  bool extended_nexthop = 16;
  SessionProtocol sessions = 17;
  bool passive = 18;
  int32 import_max_prefix = 19;
  int32 export_max_prefix = 20;
  string origin_node_id = 21;
}

message UpdatePeerRequest {
  string id = 1;
  string name = 2;
  string description = 3;
  int64 asn = 4;
  int64 local_asn = 5;
  string wg_private_key = 6;
  string wg_public_key = 7;
  string wg_remote_address = 8;
  uint32 wg_remote_port = 9;
  uint32 wg_listen_port = 10;
  string wg_interface_name = 11;
  string ipv4_tunnel_local = 12;
  string ipv4_tunnel_remote = 13;
  string ipv6_tunnel_local = 14;
  string ipv6_tunnel_remote = 15;
  bool multiprotocol = 16;
  bool extended_nexthop = 17;
  SessionProtocol sessions = 18;
  bool passive = 19;
  int32 import_max_prefix = 20;
  int32 export_max_prefix = 21;
  string origin_node_id = 22;
}

message DeletePeerRequest {
  string id = 1;
}

message DeletePeerResponse {}

message TogglePeerRequest {
  string id = 1;
}

message GenerateKeypairRequest {}

message GenerateKeypairResponse {
  string private_key = 1;
  string public_key = 2;
}

message GetConfigRequest {
  string id = 1;
}

message ConfigResponse {
  string content = 1;
}

message ExportAllRequest {}

message RestartWireGuardRequest {
  string interface_name = 1;
}

message RestartWireGuardResponse {}

// ── Settings Service Requests ──

message GetSettingsRequest {}

message SaveSettingsRequest {
  Settings settings = 1;
}

// ── Cluster Service ──

service ClusterService {
  rpc ListNodes(ListNodesRequest) returns (ListNodesResponse);
  rpc RegisterNode(RegisterNodeRequest) returns (Node);
  rpc UpdateNode(UpdateNodeRequest) returns (Node);
  rpc DeleteNode(DeleteNodeRequest) returns (DeleteNodeResponse);
  rpc PushPeer(PushPeerRequest) returns (PushPeerResponse);
  rpc PullPeers(PullPeersRequest) returns (PullPeersResponse);
  rpc PushProbeResult(PushProbeResultRequest) returns (PushProbeResultResponse);
  rpc ListProbeResults(ListProbeResultsRequest) returns (ListProbeResultsResponse);
  rpc RunProbe(RunProbeRequest) returns (RunProbeResponse);
  rpc ListCommunityRules(ListCommunityRulesRequest) returns (ListCommunityRulesResponse);
  rpc SaveCommunityRule(SaveCommunityRuleRequest) returns (CommunityRule);
  rpc DeleteCommunityRule(DeleteCommunityRuleRequest) returns (DeleteCommunityRuleResponse);
  rpc GetPeerCommunities(GetPeerCommunitiesRequest) returns (GetPeerCommunitiesResponse);
  rpc ExchangeNodes(ExchangeNodesRequest) returns (ExchangeNodesResponse);
  rpc HealthCheck(HealthCheckRequest) returns (HealthCheckResponse);
}

message Node {
  string id = 1;
  string name = 2;
  string listen_addr = 3;
  int64 local_asn = 4;
  string description = 5;
  bool online = 6;
  string last_seen_at = 7;
  string created_at = 8;
  string updated_at = 9;
}

message ProbeResult {
  string id = 1;
  string from_node_id = 2;
  string to_node_id = 3;
  double avg_latency_ms = 4;
  double min_latency_ms = 5;
  double max_latency_ms = 6;
  double packet_loss_pct = 7;
  int32 packets_sent = 8;
  int32 packets_received = 9;
  string probed_at = 10;
}

message CommunityRule {
  string id = 1;
  string description = 2;
  double max_latency_ms = 3;
  double max_packet_loss_pct = 4;
  string community_ipv4 = 5;
  string community_ipv6 = 6;
  bool enabled = 7;
  double min_bandwidth_mbps = 8;
  int32 crypto_weight = 9;
  int32 med_penalty = 10;
}

// Node CRUD
message ListNodesRequest {}
message ListNodesResponse { repeated Node nodes = 1; }
message RegisterNodeRequest {
  string name = 1;
  string listen_addr = 2;
  int64 local_asn = 3;
  string description = 4;
}
message UpdateNodeRequest {
  string id = 1;
  string name = 2;
  string listen_addr = 3;
  int64 local_asn = 4;
  string description = 5;
}
message DeleteNodeRequest { string id = 1; }
message DeleteNodeResponse {}

// Sync
message PushPeerRequest {
  Peer peer = 1;
  string origin_node_id = 2;
}
message PushPeerResponse {}
message PullPeersRequest { string since = 1; }
message PullPeersResponse { repeated Peer peers = 1; }

message PushProbeResultRequest { ProbeResult result = 1; }
message PushProbeResultResponse {}

// Probe
message ListProbeResultsRequest {
  string from_node_id = 1;
  string to_node_id = 2;
  int32 limit = 3;
}
message ListProbeResultsResponse { repeated ProbeResult results = 1; }
message RunProbeRequest {
  string from_node_id = 1;
  string to_node_id = 2;
}
message RunProbeResponse { ProbeResult result = 1; }

// Community
message ListCommunityRulesRequest {}
message ListCommunityRulesResponse { repeated CommunityRule rules = 1; }
message SaveCommunityRuleRequest { CommunityRule rule = 1; }
message DeleteCommunityRuleRequest { string id = 1; }
message DeleteCommunityRuleResponse {}

message GetPeerCommunitiesRequest { string peer_id = 1; }
message GetPeerCommunitiesResponse {
  repeated string community_ipv4 = 1;
  repeated string community_ipv6 = 2;
}

message NodeInfo {
  string name = 1;
  string listen_addr = 2;
  int64 local_asn = 3;
  string description = 4;
  string last_seen_at = 5;
  string wg_public_key = 6;
  string tunnel_ip = 7;
  string tunnel_ipv6 = 8;
}

message ExchangeNodesRequest {
  repeated NodeInfo nodes = 1;
}

message ExchangeNodesResponse {
  repeated NodeInfo nodes = 1;
}

message HealthCheckRequest {}

message HealthCheckResponse {
  bool ok = 1;
}

// ── Looking Glass Service ──

service BirdService {
  rpc ExecuteCommand(ExecuteCommandRequest) returns (ExecuteCommandResponse);
  rpc RunTraceroute(RunTracerouteRequest) returns (RunTracerouteResponse);
}

message ExecuteCommandRequest {
  string command = 1;
  string target_node_id = 2;
}

message ExecuteCommandResponse {
  repeated NodeBirdResult results = 1;
}

message NodeBirdResult {
  string node_id = 1;
  string node_name = 2;
  string output = 3;
  int32 status_code = 4;
  string error = 5;
}

message RunTracerouteRequest {
  string target = 1;
  string target_node_id = 2;
}

message RunTracerouteResponse {
  repeated NodeTracerouteResult results = 1;
}

message NodeTracerouteResult {
  string node_id = 1;
  string node_name = 2;
  string output = 3;
}

// ── Management Service ──

service ManagementService {
  rpc GetWireGuardStatus(GetWGStatusRequest) returns (WGStatusResponse);
  rpc GetBirdStatus(GetBirdStatusRequest) returns (BirdStatusResponse);
}

message GetWGStatusRequest {
  string interface = 1;
}

message WGStatusResponse {
  repeated WGInterface interfaces = 1;
}

message WGInterface {
  string name = 1;
  string public_key = 2;
  uint32 listen_port = 3;
  repeated WGPeerStatus peers = 4;
}

message WGPeerStatus {
  string public_key = 1;
  string endpoint = 2;
  string allowed_ips = 3;
  string latest_handshake = 4;
  string transfer_rx = 5;
  string transfer_tx = 6;
}

message GetBirdStatusRequest {}

message BirdStatusResponse {
  repeated BirdProtocol protocols = 1;
}

message BirdProtocol {
  string name = 1;
  string proto = 2;
  string table = 3;
  string state = 4;
  string since = 5;
  string info = 6;
}

// ── Flap Detection Service ──

service FlapService {
  rpc ListFlapEvents(ListFlapEventsRequest) returns (ListFlapEventsResponse);
  rpc GetFlapStats(GetFlapStatsRequest) returns (GetFlapStatsResponse);
}

message FlapEvent {
  string id = 1;
  string prefix = 2;
  string prefix_type = 3;
  string node_id = 4;
  int32 change_count = 5;
  string window_start = 6;
  string window_end = 7;
  string source = 8;
  bool active = 9;
  string detected_at = 10;
  string resolved_at = 11;
}

message ListFlapEventsRequest {
  bool active_only = 1;
  int32 limit = 2;
}

message ListFlapEventsResponse {
  repeated FlapEvent events = 1;
}

message GetFlapStatsRequest {}

message GetFlapStatsResponse {
  int32 active_count = 1;
  int32 total_today = 2;
  double avg_changes_per_hour = 3;
}
