export const hikvisionDefaultPort = 80;
export const hikvisionDefaultRtspPort = 554;
export const hikvisionDefaultTimeoutMs = 10000;

export type THikvisionProtocol = 'http' | 'https';
export type THikvisionAuthScheme = 'auto' | 'basic' | 'digest';
export type THikvisionHttpMethod = 'GET';
export type THikvisionCommandType =
  | 'refresh'
  | 'stream_source'
  | 'snapshot_image'
  | 'event_triggers_metadata'
  | 'subscribe_events';

export interface IHikvisionConfig {
  protocol?: THikvisionProtocol;
  ssl?: boolean;
  host?: string;
  port?: number;
  rtspPort?: number;
  username?: string;
  password?: string;
  authScheme?: THikvisionAuthScheme;
  timeoutMs?: number;
  name?: string;
  uniqueId?: string;
  model?: string;
  deviceType?: string;
  connected?: boolean;
  liveProbe?: boolean;
  fetchEventTriggers?: boolean;
  deviceInfo?: IHikvisionDeviceInfo;
  channels?: IHikvisionCameraChannel[];
  cameras?: IHikvisionCameraChannel[];
  binarySensors?: IHikvisionBinarySensor[];
  events?: IHikvisionEvent[];
  currentEventStates?: THikvisionCurrentEventStates;
  enabledEventTypes?: string[];
  snapshot?: IHikvisionSnapshot;
  metadata?: Record<string, unknown>;
}

export interface IHomeAssistantHikvisionConfig extends IHikvisionConfig {}

export interface IHikvisionDeviceInfo {
  id?: string;
  name?: string;
  manufacturer?: string;
  model?: string;
  serialNumber?: string;
  macAddress?: string;
  firmwareVersion?: string;
  deviceType?: string;
  host?: string;
  port?: number;
  protocol?: THikvisionProtocol;
  rtspPort?: number;
  online?: boolean;
  attributes?: Record<string, unknown>;
}

export interface IHikvisionCameraChannel {
  id: string;
  name?: string;
  channel?: number;
  streamingChannelId?: string;
  enabled?: boolean;
  snapshotUrl?: string;
  rtspUrl?: string;
  available?: boolean;
  attributes?: Record<string, unknown>;
}

export interface IHikvisionBinarySensor {
  key: string;
  sensorType: string;
  name?: string;
  channel: number | string;
  isOn: boolean;
  deviceClass?: string;
  entityCategory?: string;
  lastTripTime?: string | number | null;
  eventId?: string;
  triggerId?: string;
  available?: boolean;
  attributes?: Record<string, unknown>;
}

export interface IHikvisionEvent {
  id: string;
  sensorType?: string;
  key?: string;
  name?: string;
  channel?: number | string;
  state?: string;
  isOn?: boolean;
  deviceClass?: string;
  entityCategory?: string;
  eventType?: string;
  rawType?: string;
  triggerId?: string;
  updatedAt?: string;
  payload?: Record<string, unknown>;
}

export interface IHikvisionSnapshot {
  deviceInfo: IHikvisionDeviceInfo;
  cameras: IHikvisionCameraChannel[];
  binarySensors: IHikvisionBinarySensor[];
  events: IHikvisionEvent[];
  connected: boolean;
  updatedAt?: string;
  metadata?: Record<string, unknown>;
}

export interface IHikvisionSnapshotImage {
  contentType: string;
  data: Uint8Array;
}

export interface IHikvisionHttpCommand {
  label: string;
  method: THikvisionHttpMethod;
  path: string;
  expect?: 'image' | 'xml' | 'metadata';
}

export interface IHikvisionClientCommand {
  type: THikvisionCommandType;
  service: string;
  target?: {
    entityId?: string;
    deviceId?: string;
  };
  data?: Record<string, unknown>;
  cameraId?: string;
  channel?: number | string;
  streamingChannelId?: string;
  filename?: string;
  httpCommands?: IHikvisionHttpCommand[];
}

export interface IHikvisionBinarySensorDescription {
  sensorType: string;
  key: string;
  name: string;
  deviceClass?: string;
  entityCategory?: string;
}

export interface IHikvisionCurrentEventStateObject {
  channel?: number | string;
  channelId?: number | string;
  channel_id?: number | string;
  isOn?: boolean;
  on?: boolean;
  state?: unknown;
  lastTripTime?: string | number | null;
  last_trip_time?: string | number | null;
  attributes?: Record<string, unknown>;
}

export type THikvisionCurrentEventStateEntry = number | string | [unknown, number | string, unknown?, unknown?] | IHikvisionCurrentEventStateObject;
export type THikvisionCurrentEventStates = Record<string, THikvisionCurrentEventStateEntry[]>;

export interface IHikvisionManualEntry {
  host?: string;
  port?: number;
  protocol?: THikvisionProtocol;
  ssl?: boolean;
  username?: string;
  password?: string;
  id?: string;
  name?: string;
  manufacturer?: string;
  model?: string;
  deviceType?: string;
  serialNumber?: string;
  macAddress?: string;
  snapshot?: IHikvisionSnapshot;
  metadata?: Record<string, unknown>;
}

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

export interface IHikvisionSsdpRecord {
  manufacturer?: string;
  server?: string;
  st?: string;
  usn?: string;
  location?: string;
  headers?: Record<string, string | undefined>;
  upnp?: Record<string, string | undefined>;
}

export const hikvisionBinarySensorDescriptions: IHikvisionBinarySensorDescription[] = [
  { sensorType: 'Motion', key: 'motion', name: 'Motion', deviceClass: 'motion' },
  { sensorType: 'Line Crossing', key: 'line_crossing', name: 'Line crossing', deviceClass: 'motion' },
  { sensorType: 'Field Detection', key: 'field_detection', name: 'Field detection', deviceClass: 'motion' },
  { sensorType: 'Tamper Detection', key: 'tamper_detection', name: 'Tamper detection', deviceClass: 'tamper' },
  { sensorType: 'Shelter Alarm', key: 'shelter_alarm', name: 'Shelter alarm' },
  { sensorType: 'Disk Full', key: 'disk_full', name: 'Disk full', deviceClass: 'problem', entityCategory: 'diagnostic' },
  { sensorType: 'Disk Error', key: 'disk_error', name: 'Disk error', deviceClass: 'problem', entityCategory: 'diagnostic' },
  { sensorType: 'Net Interface Broken', key: 'net_interface_broken', name: 'Network interface broken', deviceClass: 'connectivity', entityCategory: 'diagnostic' },
  { sensorType: 'IP Conflict', key: 'ip_conflict', name: 'IP conflict', deviceClass: 'problem', entityCategory: 'diagnostic' },
  { sensorType: 'Illegal Access', key: 'illegal_access', name: 'Illegal access', deviceClass: 'safety' },
  { sensorType: 'Video Mismatch', key: 'video_mismatch', name: 'Video mismatch', deviceClass: 'problem', entityCategory: 'diagnostic' },
  { sensorType: 'Bad Video', key: 'bad_video', name: 'Bad video', deviceClass: 'problem', entityCategory: 'diagnostic' },
  { sensorType: 'PIR Alarm', key: 'pir_alarm', name: 'PIR alarm', deviceClass: 'motion' },
  { sensorType: 'Face Detection', key: 'face_detection', name: 'Face detection', deviceClass: 'motion' },
  { sensorType: 'Scene Change Detection', key: 'scene_change_detection', name: 'Scene change detection', deviceClass: 'motion' },
  { sensorType: 'I/O', key: 'io', name: 'I/O alarm' },
  { sensorType: 'Unattended Baggage', key: 'unattended_baggage', name: 'Unattended baggage', deviceClass: 'motion' },
  { sensorType: 'Attended Baggage', key: 'attended_baggage', name: 'Attended baggage', deviceClass: 'motion' },
  { sensorType: 'Recording Failure', key: 'recording_failure', name: 'Recording failure', deviceClass: 'problem', entityCategory: 'diagnostic' },
  { sensorType: 'Exiting Region', key: 'exiting_region', name: 'Exiting region', deviceClass: 'motion' },
  { sensorType: 'Entering Region', key: 'entering_region', name: 'Entering region', deviceClass: 'motion' },
];

export const hikvisionRawEventTypeMap: Record<string, string> = {
  vmd: 'Motion',
  motion: 'Motion',
  videomotion: 'Motion',
  linedetection: 'Line Crossing',
  linecrossing: 'Line Crossing',
  line_crossing: 'Line Crossing',
  crossline: 'Line Crossing',
  crosslinedetection: 'Line Crossing',
  fielddetection: 'Field Detection',
  field_detection: 'Field Detection',
  intrusiondetection: 'Field Detection',
  fielddetectionregion: 'Field Detection',
  tamperdetection: 'Tamper Detection',
  tamper: 'Tamper Detection',
  shelteralarm: 'Shelter Alarm',
  diskfull: 'Disk Full',
  hddfull: 'Disk Full',
  diskerror: 'Disk Error',
  hdderror: 'Disk Error',
  netinterfacebroken: 'Net Interface Broken',
  networkinterfacebroken: 'Net Interface Broken',
  networkbroken: 'Net Interface Broken',
  ipconflict: 'IP Conflict',
  illegalaccess: 'Illegal Access',
  videomismatch: 'Video Mismatch',
  badvideo: 'Bad Video',
  pir: 'PIR Alarm',
  piralarm: 'PIR Alarm',
  facedetection: 'Face Detection',
  scenechangedetection: 'Scene Change Detection',
  io: 'I/O',
  ioalarm: 'I/O',
  alarminput: 'I/O',
  unattendedbaggage: 'Unattended Baggage',
  attendedbaggage: 'Attended Baggage',
  recordingfailure: 'Recording Failure',
  exitingregion: 'Exiting Region',
  regionexiting: 'Exiting Region',
  enteringregion: 'Entering Region',
  regionentrance: 'Entering Region',
};
