export const homematicDefaultInterfacePort = 2001;
export const homematicDefaultJsonPort = 80;

export type THomematicProtocol = 'http' | 'https';
export type THomematicSnapshotSource = 'snapshot' | 'manual' | 'xmlrpc' | 'runtime';
export type THomematicValueType = 'boolean' | 'integer' | 'double' | 'string' | 'dateTime.iso8601' | 'array' | 'struct' | 'unknown';
export type THomematicDatapointKind = 'sensor' | 'binary' | 'attribute' | 'write' | 'action' | 'event' | 'unknown';
export type THomematicParamsetKey = 'VALUES' | 'MASTER' | 'LINK' | (string & {});
export type THomematicInterfaceFamily = 'bidcos-rf' | 'hmip-rf' | 'bidcos-wired' | 'virtual' | 'homegear' | 'unknown' | (string & {});

export type THomematicEventType =
  | 'snapshot_refreshed'
  | 'command_mapped'
  | 'command_executed'
  | 'command_failed'
  | 'datapoint_changed'
  | 'keypress'
  | 'impulse'
  | 'error';

export type IHomematicValue = string | number | boolean | null | Record<string, unknown> | unknown[];

export interface IHomematicConfig {
  host?: string;
  port?: number;
  path?: string;
  ssl?: boolean;
  verifySsl?: boolean;
  username?: string;
  password?: string;
  jsonPort?: number;
  timeoutMs?: number;
  name?: string;
  uniqueId?: string;
  localIp?: string;
  localPort?: number;
  callbackIp?: string;
  callbackPort?: number;
  interfaceId?: string;
  interfaceName?: string;
  resolvenames?: 'metadata' | 'json' | 'xml' | false;
  connected?: boolean;
  ccu?: IHomematicCcu;
  interfaces?: Record<string, IHomematicInterfaceConfig>;
  devices?: IHomematicDevice[];
  events?: IHomematicEvent[];
  snapshot?: IHomematicSnapshot;
  commandExecutor?: (commandArg: IHomematicCommand) => Promise<IHomematicCommandResult | unknown>;
}

export interface IHomeAssistantHomematicConfig extends IHomematicConfig {}

export interface IHomematicInterfaceConfig {
  id?: string;
  name?: string;
  host?: string;
  port?: number;
  path?: string;
  protocol?: THomematicProtocol;
  ssl?: boolean;
  verifySsl?: boolean;
  username?: string;
  password?: string;
  jsonPort?: number;
  resolvenames?: 'metadata' | 'json' | 'xml' | false;
  connect?: boolean;
  family?: THomematicInterfaceFamily;
  callbackIp?: string;
  callbackPort?: number;
  attributes?: Record<string, unknown>;
}

export interface IHomematicCcu {
  id?: string;
  name?: string;
  host?: string;
  port?: number;
  manufacturer?: string;
  model?: string;
  serialNumber?: string;
  firmwareVersion?: string;
  online?: boolean;
  serviceMessages?: IHomematicServiceMessage[];
  variables?: Record<string, IHomematicValue>;
  attributes?: Record<string, unknown>;
}

export interface IHomematicServiceMessage {
  address?: string;
  channel?: number;
  parameter?: string;
  message?: string;
  value?: IHomematicValue;
  attributes?: Record<string, unknown>;
}

export interface IHomematicInterface {
  id: string;
  name: string;
  host?: string;
  port?: number;
  path?: string;
  protocol?: THomematicProtocol;
  family?: THomematicInterfaceFamily;
  online: boolean;
  attributes?: Record<string, unknown>;
}

export interface IHomematicDevice {
  address: string;
  name?: string;
  type?: string;
  interfaceName?: string;
  manufacturer?: string;
  model?: string;
  serialNumber?: string;
  firmwareVersion?: string;
  available?: boolean;
  unreach?: boolean;
  channels: IHomematicChannel[];
  datapoints?: IHomematicDatapoint[];
  paramsets?: THomematicParamsetKey[];
  attributes?: Record<string, unknown>;
  raw?: Record<string, unknown>;
}

export interface IHomematicChannel {
  address: string;
  index: number;
  name?: string;
  type?: string;
  parentAddress?: string;
  datapoints: IHomematicDatapoint[];
  paramsets?: THomematicParamsetKey[];
  attributes?: Record<string, unknown>;
  raw?: Record<string, unknown>;
}

export interface IHomematicDatapoint {
  name: string;
  value?: IHomematicValue;
  valueType?: THomematicValueType;
  channel?: number;
  address?: string;
  kind?: THomematicDatapointKind;
  paramsetKey?: THomematicParamsetKey;
  operations?: number;
  readable?: boolean;
  writable?: boolean;
  eventable?: boolean;
  unit?: string;
  min?: number;
  max?: number;
  valueList?: string[];
  deviceClass?: string;
  stateClass?: string;
  updatedAt?: string;
  attributes?: Record<string, unknown>;
}

export interface IHomematicSnapshot {
  ccu: IHomematicCcu;
  interfaces: IHomematicInterface[];
  devices: IHomematicDevice[];
  events: IHomematicEvent[];
  connected: boolean;
  updatedAt: string;
  source: THomematicSnapshotSource;
  raw?: Record<string, unknown>;
}

export interface IHomematicEvent {
  type: THomematicEventType;
  interfaceName?: string;
  address?: string;
  channel?: number;
  datapoint?: string;
  value?: IHomematicValue;
  command?: IHomematicCommand;
  entityId?: string;
  deviceId?: string;
  data?: unknown;
  timestamp: number;
}

export type IHomematicCommand =
  | IHomematicSetValueCommand
  | IHomematicPressCommand
  | IHomematicTurnCommand
  | IHomematicCoverCommand
  | IHomematicSetTemperatureCommand
  | IHomematicRefreshCommand
  | IHomematicRawXmlRpcCommand;

export interface IHomematicCommandBase {
  interfaceName?: string;
  address?: string;
  channel?: number;
  entityId?: string;
  deviceId?: string;
  uniqueId?: string;
}

export interface IHomematicSetValueCommand extends IHomematicCommandBase {
  type: 'set_value';
  address: string;
  datapoint: string;
  value: IHomematicValue;
  valueType?: THomematicValueType;
}

export interface IHomematicPressCommand extends IHomematicCommandBase {
  type: 'press';
  address: string;
  channel: number;
  datapoint: string;
  value?: IHomematicValue;
}

export interface IHomematicTurnCommand extends IHomematicCommandBase {
  type: 'turn_on' | 'turn_off';
  address: string;
  channel: number;
  datapoint: string;
  value: IHomematicValue;
}

export interface IHomematicCoverCommand extends IHomematicCommandBase {
  type: 'open' | 'close' | 'stop';
  address: string;
  channel: number;
  datapoint: string;
  value: IHomematicValue;
}

export interface IHomematicSetTemperatureCommand extends IHomematicCommandBase {
  type: 'set_temperature';
  address: string;
  channel: number;
  datapoint: string;
  value: number;
}

export interface IHomematicRefreshCommand {
  type: 'refresh';
}

export interface IHomematicRawXmlRpcCommand extends IHomematicCommandBase {
  type: 'raw_xmlrpc';
  method: string;
  params?: unknown[];
}

export interface IHomematicCommandResult {
  success: boolean;
  error?: string;
  data?: unknown;
}

export interface IHomematicXmlRpcCommandShape {
  protocol: 'xmlrpc';
  endpoint: string;
  method: 'POST';
  contentType: 'text/xml';
  xmlRpcMethod: string;
  params: unknown[];
  interfaceName?: string;
  host?: string;
  port?: number;
  path?: string;
}

export interface IHomematicManualEntry {
  host?: string;
  port?: number;
  path?: string;
  ssl?: boolean;
  username?: string;
  password?: string;
  id?: string;
  name?: string;
  manufacturer?: string;
  model?: string;
  serialNumber?: string;
  macAddress?: string;
  interfaceName?: string;
  metadata?: Record<string, unknown>;
}

export interface IHomematicMetadataDiscoveryRecord {
  domain?: string;
  integrationDomain?: string;
  name?: string;
  manufacturer?: string;
  model?: string;
  host?: string;
  port?: number;
  metadata?: Record<string, unknown>;
  [key: string]: unknown;
}

export interface IHomematicXmlRpcDeviceDescription {
  ADDRESS?: string;
  TYPE?: string;
  PARENT?: string;
  PARENT_TYPE?: string;
  INDEX?: number;
  PARAMSETS?: string[];
  CHILDREN?: string[];
  VERSION?: number;
  FIRMWARE?: string;
  AVAILABLE_FIRMWARE?: string;
  DIRECTION?: number;
  AES_ACTIVE?: number | boolean;
  LINK_SOURCE_ROLES?: string;
  LINK_TARGET_ROLES?: string;
  CHANNEL?: number;
  INTERFACE?: string;
  FLAGS?: number;
  ID?: string;
  [key: string]: unknown;
}

export interface IHomematicXmlRpcParamsetDescription {
  TYPE?: string;
  OPERATIONS?: number;
  MIN?: number;
  MAX?: number;
  UNIT?: string;
  DEFAULT?: IHomematicValue;
  VALUE_LIST?: string[];
  [key: string]: unknown;
}
