export type TModbusTransport = 'tcp' | 'udp' | 'rtuovertcp' | 'serial';

export type TModbusRegisterType = 'holding' | 'input';

export type TModbusCoilType = 'coil' | 'discrete_input';

export type TModbusDataType =
  | 'custom'
  | 'string'
  | 'int'
  | 'integer'
  | 'int16'
  | 'int32'
  | 'int64'
  | 'uint'
  | 'uint16'
  | 'uint32'
  | 'uint64'
  | 'float'
  | 'float16'
  | 'float32'
  | 'float64';

export type TModbusSwap = 'byte' | 'word' | 'word_byte';

export type TModbusEntityPlatform = 'sensor' | 'binary_sensor' | 'switch' | 'number';

export type TModbusEventType =
  | 'snapshot_refreshed'
  | 'command_mapped'
  | 'command_executed'
  | 'command_failed'
  | 'register_read'
  | 'register_written'
  | 'coil_read'
  | 'coil_written';

export interface IModbusConfig {
  hubs?: IModbusHubConfig[];
  modbus?: IModbusHubConfig[];
  snapshot?: IModbusSnapshot;
  manualEntries?: IModbusManualTcpEntry[];
  connected?: boolean;
  timeoutMs?: number;
  commandExecutor?: (commandArg: IModbusCommand) => Promise<IModbusCommandResult | unknown>;
}

export interface IHomeAssistantModbusConfig extends IModbusConfig {}

export interface IModbusHubConfig {
  id?: string;
  name?: string;
  type?: TModbusTransport;
  host?: string;
  port?: number | string;
  timeout?: number;
  timeoutMs?: number;
  delay?: number;
  messageWaitMilliseconds?: number;
  message_wait_milliseconds?: number;
  slave?: number;
  unit?: number;
  unitId?: number;
  deviceAddress?: number;
  device_address?: number;
  connected?: boolean;
  manufacturer?: string;
  model?: string;
  serialNumber?: string;
  serial_number?: string;
  metadata?: Record<string, unknown>;
  slaves?: IModbusSlaveConfig[];
  registers?: IModbusRegisterConfig[];
  coils?: IModbusCoilConfig[];
  sensors?: IModbusRegisterConfig[];
  binarySensors?: IModbusCoilConfig[];
  binary_sensors?: IModbusCoilConfig[];
  switches?: IModbusSwitchConfig[];
  numbers?: IModbusNumberConfig[];
}

export interface IModbusSlaveConfig {
  id?: string;
  unitId?: number;
  unit?: number;
  slave?: number;
  deviceAddress?: number;
  device_address?: number;
  name?: string;
  connected?: boolean;
  manufacturer?: string;
  model?: string;
  serialNumber?: string;
  serial_number?: string;
  metadata?: Record<string, unknown>;
}

export interface IModbusEntityConfigBase {
  id?: string;
  name: string;
  uniqueId?: string;
  unique_id?: string;
  platform?: TModbusEntityPlatform;
  address: number;
  slave?: number;
  unit?: number;
  unitId?: number;
  deviceAddress?: number;
  device_address?: number;
  scanInterval?: number;
  scan_interval?: number;
  deviceClass?: string;
  device_class?: string;
  available?: boolean;
  metadata?: Record<string, unknown>;
}

export interface IModbusRegisterConfig extends IModbusEntityConfigBase {
  platform?: 'sensor' | 'number';
  inputType?: TModbusRegisterType;
  input_type?: TModbusRegisterType;
  registerType?: TModbusRegisterType;
  register_type?: TModbusRegisterType;
  count?: number;
  dataType?: TModbusDataType;
  data_type?: TModbusDataType;
  structure?: string;
  scale?: number;
  offset?: number;
  precision?: number;
  swap?: TModbusSwap;
  unitOfMeasurement?: string;
  unit_of_measurement?: string;
  stateClass?: string;
  state_class?: string;
  minValue?: number;
  min_value?: number;
  maxValue?: number;
  max_value?: number;
  nanValue?: number;
  nan_value?: number;
  zeroSuppress?: number;
  zero_suppress?: number;
  min?: number;
  max?: number;
  step?: number;
  writable?: boolean;
  value?: number | string | null;
  registers?: number[];
}

export interface IModbusNumberConfig extends IModbusRegisterConfig {
  platform?: 'number';
  writable?: true;
}

export interface IModbusCoilConfig extends IModbusEntityConfigBase {
  platform?: 'binary_sensor' | 'switch';
  inputType?: TModbusCoilType | TModbusRegisterType;
  input_type?: TModbusCoilType | TModbusRegisterType;
  coilType?: TModbusCoilType;
  coil_type?: TModbusCoilType;
  count?: number;
  slaveCount?: number;
  slave_count?: number;
  virtualCount?: number;
  virtual_count?: number;
  writable?: boolean;
  value?: boolean | number | null;
  bits?: boolean[];
}

export interface IModbusSwitchConfig extends IModbusCoilConfig {
  platform?: 'switch';
  writeType?: TModbusWriteType;
  write_type?: TModbusWriteType;
  commandOn?: number;
  command_on?: number;
  commandOff?: number;
  command_off?: number;
  stateOn?: number[];
  state_on?: number[];
  stateOff?: number[];
  state_off?: number[];
  verify?: IModbusSwitchVerifyConfig | null;
}

export interface IModbusSwitchVerifyConfig {
  address?: number;
  inputType?: TModbusCoilType | TModbusRegisterType;
  input_type?: TModbusCoilType | TModbusRegisterType;
  delay?: number;
  stateOn?: number[];
  state_on?: number[];
  stateOff?: number[];
  state_off?: number[];
}

export type TModbusWriteType = 'holding' | 'holdings' | 'coil' | 'coils';

export interface IModbusRegisterState {
  hubId?: string;
  unitId: number;
  address: number;
  count: number;
  inputType: TModbusRegisterType;
  dataType: TModbusDataType;
  registers?: number[];
  value?: number | string | number[] | null;
  updatedAt?: string;
  metadata?: Record<string, unknown>;
}

export interface IModbusCoilState {
  hubId?: string;
  unitId: number;
  address: number;
  count: number;
  inputType: TModbusCoilType | TModbusRegisterType;
  bits?: boolean[];
  value?: boolean | number | null;
  updatedAt?: string;
  metadata?: Record<string, unknown>;
}

export interface IModbusEntitySnapshot {
  id: string;
  name: string;
  uniqueId: string;
  platform: TModbusEntityPlatform;
  hubId: string;
  hubName: string;
  unitId: number;
  address: number;
  available: boolean;
  writable: boolean;
  register?: IModbusRegisterState;
  coil?: IModbusCoilState;
  state?: unknown;
  attributes?: Record<string, unknown>;
}

export interface IModbusSlaveSnapshot {
  id: string;
  hubId: string;
  unitId: number;
  name: string;
  online: boolean;
  manufacturer?: string;
  model?: string;
  serialNumber?: string;
  registers: IModbusRegisterState[];
  coils: IModbusCoilState[];
  metadata?: Record<string, unknown>;
}

export interface IModbusHubSnapshot {
  id: string;
  name: string;
  type: TModbusTransport;
  host?: string;
  port?: number | string;
  online: boolean;
  manufacturer?: string;
  model?: string;
  serialNumber?: string;
  unsupportedReason?: string;
  slaves: IModbusSlaveSnapshot[];
  registers: IModbusRegisterState[];
  coils: IModbusCoilState[];
  entities: IModbusEntitySnapshot[];
  metadata?: Record<string, unknown>;
}

export interface IModbusSnapshot {
  hubs: IModbusHubSnapshot[];
  events: IModbusEvent[];
  connected: boolean;
  updatedAt: string;
  raw?: Record<string, unknown>;
}

export interface IModbusEvent {
  type: TModbusEventType;
  command?: IModbusCommand;
  hubId?: string;
  hubName?: string;
  unitId?: number;
  entityId?: string;
  deviceId?: string;
  uniqueId?: string;
  data?: unknown;
  timestamp: number;
}

export type IModbusCommand =
  | IModbusRefreshCommand
  | IModbusReadRegisterCommand
  | IModbusWriteRegisterCommand
  | IModbusReadCoilCommand
  | IModbusWriteCoilCommand
  | IModbusStopCommand
  | IModbusRestartCommand;

export interface IModbusCommandBase {
  hub?: string;
  hubId?: string;
  unitId?: number;
  slave?: number;
  entityId?: string;
  deviceId?: string;
  uniqueId?: string;
}

export interface IModbusRefreshCommand extends IModbusCommandBase {
  type: 'refresh';
}

export interface IModbusStopCommand extends IModbusCommandBase {
  type: 'stop';
}

export interface IModbusRestartCommand extends IModbusCommandBase {
  type: 'restart';
}

export interface IModbusReadRegisterCommand extends IModbusCommandBase {
  type: 'read_register';
  address: number;
  count?: number;
  inputType?: TModbusRegisterType;
  dataType?: TModbusDataType;
}

export interface IModbusWriteRegisterCommand extends IModbusCommandBase {
  type: 'write_register';
  address: number;
  value: number | number[];
}

export interface IModbusReadCoilCommand extends IModbusCommandBase {
  type: 'read_coil';
  address: number;
  count?: number;
  inputType?: TModbusCoilType;
}

export interface IModbusWriteCoilCommand extends IModbusCommandBase {
  type: 'write_coil';
  address: number;
  value: boolean | boolean[] | number | number[];
}

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

export interface IModbusTcpCommandShape {
  transport: 'tcp';
  host?: string;
  port?: number;
  unitId: number;
  transactionId: number;
  functionCode: number;
  functionName: string;
  address?: number;
  quantity?: number;
  values?: number[] | boolean[];
  mbap: {
    transactionId: number;
    protocolId: 0;
    length: number;
    unitId: number;
  };
  pduHex: string;
  requestHex: string;
}

export interface IModbusTcpResponse {
  transactionId: number;
  unitId: number;
  functionCode: number;
  registers?: number[];
  bits?: boolean[];
  address?: number;
  quantity?: number;
  rawHex: string;
}

export interface IModbusManualTcpEntry {
  host?: string;
  port?: number;
  type?: TModbusTransport;
  protocol?: string;
  name?: string;
  id?: string;
  unitId?: number;
  slave?: number;
  manufacturer?: string;
  model?: string;
  serialNumber?: string;
  metadata?: Record<string, unknown>;
}

export interface IModbusDiscoveryEntry extends IModbusManualTcpEntry {}
