export type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };

export type ProviderLabels = Record<string, JsonValue>;

export interface ProviderRegisterMessage {
  type: "register";
  providerId: string;
  name: string;
  labels: ProviderLabels;
  startedAt: string;
  capabilities: string[];
}

export interface ProviderHeartbeatMessage {
  type: "heartbeat";
  providerId: string;
  labels: ProviderLabels;
  at: string;
}

export interface ProcessResourceSummary {
  pid: number;
  ppid: number;
  uid: number;
  user: string;
  name: string;
  command: string;
  state: string;
  cpuPercent: number;
  memoryPercent: number;
  memoryBytes: number;
  memoryMode: string;
  rssBytes: number;
  pssBytes?: number;
  privateBytes?: number;
  sharedBytes?: number;
  swapPssBytes?: number;
  vmsBytes: number;
  threads: number;
  readBytes: number;
  writeBytes: number;
  readBytesPerSecond: number;
  writeBytesPerSecond: number;
  elapsedSeconds: number;
  startedAt: string;
}

export interface SystemStatusSnapshot {
  ok: boolean;
  collectedAt: string;
  cpu: Record<string, JsonValue>;
  memory: Record<string, JsonValue>;
  disk: Record<string, JsonValue>;
  processes?: ProcessResourceSummary[];
  processSummary?: Record<string, JsonValue>;
  errors: JsonValue[];
}

export interface ProviderSystemStatusMessage {
  type: "system_status";
  providerId: string;
  at: string;
  status: SystemStatusSnapshot;
}

export interface DockerContainerSummary {
  id: string;
  name: string;
  image: string;
  state: string;
  status: string;
  ports: string;
  createdAt: string;
  runningFor: string;
  size: string;
  networks: string;
  restartPolicy?: string;
  restartPolicyMaximumRetryCount?: number;
  pidMode?: string;
  composeProject?: string;
  composeService?: string;
  labels?: Record<string, string>;
}

export interface DockerImageSummary {
  id: string;
  repository: string;
  tag: string;
  size: string;
  createdSince: string;
  containers: string;
}

export interface DockerVolumeSummary {
  name: string;
  driver: string;
  scope: string;
  mountpoint: string;
  labels: string;
  size: string;
  status: string;
}

export interface DockerNetworkSummary {
  id: string;
  name: string;
  driver: string;
  scope: string;
  internal: string;
  ipv4: string;
  ipv6: string;
}

export interface DockerStatusSnapshot {
  ok: boolean;
  socketPresent: boolean;
  collectedAt: string;
  daemon: Record<string, JsonValue>;
  counts: Record<string, JsonValue>;
  containers: DockerContainerSummary[];
  images: DockerImageSummary[];
  volumes: DockerVolumeSummary[];
  networks: DockerNetworkSummary[];
  errors: JsonValue[];
}

export interface ProviderDockerStatusMessage {
  type: "docker_status";
  providerId: string;
  at: string;
  status: DockerStatusSnapshot;
}

export interface ProviderTaskStatusMessage {
  type: "task_status";
  providerId: string;
  taskId: string;
  status: "accepted" | "running" | "succeeded" | "failed";
  message: string;
  at: string;
  result?: JsonValue;
}

export type ProviderDispatchCommand = "docker.ps" | "provider.upgrade" | "host.ssh" | "microservice.http" | "echo";

export interface CoreDispatchMessage {
  type: "dispatch";
  taskId: string;
  command: ProviderDispatchCommand;
  payload: Record<string, JsonValue>;
}

export interface CoreHostSshOpenMessage {
  type: "host_ssh_open";
  sessionId: string;
  transport: "tcp-pool";
  dataChannelId: string;
  cwd?: string;
  command?: string;
  tty?: boolean;
  cols?: number;
  rows?: number;
}

export interface CoreAcknowledgeMessage {
  type: "ack";
  requestId: string;
  ok: boolean;
  message: string;
}

export interface ProviderHostSshErrorMessage {
  type: "host_ssh_error";
  providerId: string;
  sessionId: string;
  message: string;
  at: string;
}

export interface ProviderEgressTcpOpenMessage {
  type: "egress_tcp_open";
  providerId: string;
  connectionId: string;
  host: string;
  port: number;
  at: string;
}

export interface ProviderEgressTcpDataMessage {
  type: "egress_tcp_data";
  providerId: string;
  connectionId: string;
  data: string;
  encoding: "base64";
  at: string;
}

export interface ProviderEgressTcpCloseMessage {
  type: "egress_tcp_close";
  providerId: string;
  connectionId: string;
  at: string;
}

export interface CoreHttpTunnelRequestMessage {
  type: "http_tunnel_request";
  requestId: string;
  payload: Record<string, JsonValue>;
}

export interface ProviderHttpTunnelResponseMessage {
  type: "http_tunnel_response";
  providerId: string;
  requestId: string;
  ok: boolean;
  result: JsonValue;
  at: string;
}

export interface CoreEgressTcpOpenedMessage {
  type: "egress_tcp_opened";
  connectionId: string;
}

export interface CoreEgressTcpDataMessage {
  type: "egress_tcp_data";
  connectionId: string;
  data: string;
  encoding: "base64";
}

export interface CoreEgressTcpCloseMessage {
  type: "egress_tcp_close";
  connectionId: string;
  error?: string;
}

export type ProviderToCoreMessage =
  | ProviderRegisterMessage
  | ProviderHeartbeatMessage
  | ProviderSystemStatusMessage
  | ProviderDockerStatusMessage
  | ProviderTaskStatusMessage
  | ProviderHostSshErrorMessage
  | ProviderEgressTcpOpenMessage
  | ProviderEgressTcpDataMessage
  | ProviderEgressTcpCloseMessage
  | ProviderHttpTunnelResponseMessage;

export type CoreToProviderMessage =
  | CoreDispatchMessage
  | CoreHttpTunnelRequestMessage
  | CoreHostSshOpenMessage
  | CoreEgressTcpOpenedMessage
  | CoreEgressTcpDataMessage
  | CoreEgressTcpCloseMessage
  | CoreAcknowledgeMessage;

export interface ApiNode {
  providerId: string;
  name: string;
  status: "online" | "offline";
  labels: ProviderLabels;
  connectedAt: string | null;
  lastHeartbeat: string | null;
}

export interface ApiNodeDockerStatus {
  providerId: string;
  name: string;
  nodeStatus: "online" | "offline";
  dockerStatus: JsonValue | null;
  updatedAt: string | null;
}

export interface ApiNodeSystemStatus {
  providerId: string;
  name: string;
  nodeStatus: "online" | "offline";
  current: JsonValue | null;
  lastKnown?: JsonValue | null;
  currentCollectedAt?: string | null;
  stale?: boolean;
  staleSeconds?: number | null;
  history: JsonValue[];
  updatedAt: string | null;
}

export interface ApiTask {
  id: string;
  providerId: string;
  command: string;
  status: string;
  payload: JsonValue;
  result: JsonValue;
  createdAt: string;
  updatedAt: string;
}

export interface ApiEvent {
  id: number;
  type: string;
  source: string;
  payload: JsonValue;
  createdAt: string;
}

export interface ServiceLogEntry {
  ts: string;
  service: string;
  level: "debug" | "info" | "warn" | "error";
  message: string;
  data?: JsonValue;
}

export function parseJsonObject(value: string, name: string): Record<string, JsonValue> {
  const parsed = JSON.parse(value) as unknown;
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
    throw new Error(`${name} must be a JSON object`);
  }
  return parsed as Record<string, JsonValue>;
}

export function isProviderDispatchCommand(value: unknown): value is ProviderDispatchCommand {
  return value === "docker.ps" || value === "provider.upgrade" || value === "host.ssh" || value === "microservice.http" || value === "echo";
}

export function isProviderToCoreMessage(value: unknown): value is ProviderToCoreMessage {
  if (typeof value !== "object" || value === null || !("type" in value)) return false;
  const msg = value as { type?: unknown; providerId?: unknown };
  return (
    (
      msg.type === "register" ||
      msg.type === "heartbeat" ||
      msg.type === "system_status" ||
      msg.type === "docker_status" ||
      msg.type === "task_status" ||
      msg.type === "host_ssh_error" ||
      msg.type === "egress_tcp_open" ||
      msg.type === "egress_tcp_data" ||
      msg.type === "egress_tcp_close" ||
      msg.type === "http_tunnel_response"
    ) &&
    typeof msg.providerId === "string" &&
    msg.providerId.length > 0
  );
}
