export const snapcastTcpControlPort = 1705;
export const snapcastHttpControlPort = 1780;

export type TSnapcastRpcTransport = 'tcp' | 'http' | 'https' | 'snapshot';
export type TSnapcastStreamStatus = 'idle' | 'playing' | 'unknown' | (string & {});

export type TSnapcastRpcMethod =
  | 'Client.GetStatus'
  | 'Client.SetVolume'
  | 'Client.SetLatency'
  | 'Client.SetName'
  | 'Group.GetStatus'
  | 'Group.SetMute'
  | 'Group.SetStream'
  | 'Group.SetClients'
  | 'Group.SetName'
  | 'Server.GetRPCVersion'
  | 'Server.GetStatus'
  | 'Server.DeleteClient'
  | 'Stream.Control'
  | 'Stream.SetProperty'
  | 'Stream.AddStream'
  | 'Stream.RemoveStream';

export type TSnapcastEventMethod =
  | 'Client.OnConnect'
  | 'Client.OnDisconnect'
  | 'Client.OnVolumeChanged'
  | 'Client.OnLatencyChanged'
  | 'Client.OnNameChanged'
  | 'Group.OnMute'
  | 'Group.OnStreamChanged'
  | 'Group.OnNameChanged'
  | 'Stream.OnProperties'
  | 'Stream.OnUpdate'
  | 'Server.OnUpdate';

export type TSnapcastServiceCommand =
  | 'volume_set'
  | 'volume_mute'
  | 'set_latency'
  | 'set_stream'
  | 'set_group_mute'
  | 'set_clients'
  | 'join'
  | 'unjoin'
  | 'snapshot'
  | 'restore';

export interface ISnapcastConfig {
  host?: string;
  port?: number;
  transport?: TSnapcastRpcTransport;
  timeoutMs?: number;
  serverId?: string;
  snapshot?: ISnapcastSnapshot;
}

export interface IHomeAssistantSnapcastConfig extends ISnapcastConfig {}

export interface ISnapcastSnapshot {
  server: ISnapcastServerStatus;
  capturedAt?: string;
  source?: 'manual' | 'jsonrpc' | 'runtime';
}

export interface ISnapcastServerStatus {
  groups: ISnapcastGroup[];
  streams: ISnapcastStream[];
  server?: ISnapcastServerInfo;
}

export interface ISnapcastServerInfo {
  host?: ISnapcastHostInfo;
  snapserver?: {
    name?: string;
    version?: string;
    protocolVersion?: number;
    controlProtocolVersion?: number;
  };
}

export interface ISnapcastHostInfo {
  arch?: string;
  ip?: string;
  mac?: string;
  name?: string;
  os?: string;
}

export interface ISnapcastVolume {
  muted: boolean;
  percent: number;
}

export interface ISnapcastClientConfig {
  instance?: number;
  latency?: number;
  name?: string;
  volume?: ISnapcastVolume;
}

export interface ISnapcastClient {
  id: string;
  connected: boolean;
  host?: ISnapcastHostInfo;
  config: ISnapcastClientConfig;
  lastSeen?: {
    sec?: number;
    usec?: number;
  };
  snapclient?: {
    name?: string;
    version?: string;
    protocolVersion?: number;
  };
}

export interface ISnapcastGroup {
  id: string;
  clients: ISnapcastClient[];
  muted?: boolean;
  name?: string;
  stream_id?: string;
  streamId?: string;
}

export interface ISnapcastStreamUri {
  raw?: string;
  scheme?: string;
  host?: string;
  path?: string;
  fragment?: string;
  query?: Record<string, string | undefined>;
}

export interface ISnapcastMediaMetadata {
  title?: string;
  artist?: string[] | string;
  album?: string;
  albumArtist?: string[] | string;
  artUrl?: string;
  trackNumber?: number | string;
  duration?: number | string;
  [key: string]: unknown;
}

export interface ISnapcastStream {
  id: string;
  status?: TSnapcastStreamStatus;
  uri?: ISnapcastStreamUri;
  metadata?: ISnapcastMediaMetadata;
  properties?: Record<string, unknown>;
}

export interface ISnapcastRpcRequest<TParams = Record<string, unknown>> {
  id: number | string;
  jsonrpc: '2.0';
  method: TSnapcastRpcMethod | string;
  params?: TParams;
}

export interface ISnapcastRpcError {
  code: number;
  message: string;
  data?: unknown;
}

export interface ISnapcastRpcResponse<TResult = unknown> {
  id?: number | string;
  jsonrpc?: '2.0';
  result?: TResult;
  error?: ISnapcastRpcError;
}

export interface ISnapcastRpcNotification<TParams = Record<string, unknown>> {
  jsonrpc?: '2.0';
  method: TSnapcastEventMethod | string;
  params?: TParams;
}

export interface ISnapcastClientVolumeCommand {
  clientId: string;
  percent?: number;
  muted?: boolean;
}

export interface ISnapcastClientLatencyCommand {
  clientId: string;
  latency: number;
}

export interface ISnapcastSetStreamCommand {
  groupId: string;
  streamId: string;
}

export interface ISnapcastSetGroupClientsCommand {
  groupId: string;
  clientIds: string[];
}

export interface ISnapcastStreamControlCommand {
  streamId: string;
  command: 'next' | 'previous' | 'pause' | 'playPause' | 'stop' | 'play' | 'seek' | 'setPosition' | (string & {});
  params?: Record<string, unknown>;
}

export interface ISnapcastClientEvent {
  method: Extract<TSnapcastEventMethod, `Client.${string}`>;
  clientId?: string;
  client?: ISnapcastClient;
  volume?: ISnapcastVolume;
  latency?: number;
  name?: string;
}

export interface ISnapcastGroupEvent {
  method: Extract<TSnapcastEventMethod, `Group.${string}`>;
  groupId?: string;
  muted?: boolean;
  streamId?: string;
  name?: string;
}

export interface ISnapcastStreamEvent {
  method: Extract<TSnapcastEventMethod, `Stream.${string}`>;
  streamId?: string;
  stream?: ISnapcastStream;
  properties?: Record<string, unknown>;
}

export interface ISnapcastServerEvent {
  method: 'Server.OnUpdate';
  server?: ISnapcastServerStatus;
}

export type TSnapcastEvent = ISnapcastClientEvent | ISnapcastGroupEvent | ISnapcastStreamEvent | ISnapcastServerEvent;

export interface ISnapcastMdnsRecord {
  name?: string;
  type?: string;
  serviceType?: string;
  host?: string;
  port?: number;
  addresses?: string[];
  txt?: Record<string, string | undefined>;
}

export interface ISnapcastManualEntry {
  host?: string;
  port?: number;
  id?: string;
  name?: string;
  transport?: TSnapcastRpcTransport;
  manufacturer?: string;
  model?: string;
  metadata?: Record<string, unknown>;
}

export interface ISnapcastDiscoveryRecord {
  source: 'mdns' | 'manual';
  host?: string;
  port?: number;
  transport?: TSnapcastRpcTransport;
  mdnsType?: string;
  name?: string;
  id?: string;
}
