export const foscamDomain = 'foscam';
export const foscamDefaultPort = 88;
export const foscamDefaultRtspPort = 88;
export const foscamDefaultTimeoutMs = 10000;
export const foscamDefaultSnapshotTimeoutMs = 20000;

export const foscamStreams = ['Main', 'Sub'] as const;
export const foscamPtzMovements = [
  'up',
  'down',
  'left',
  'right',
  'top_left',
  'top_right',
  'bottom_left',
  'bottom_right',
] as const;

export type TFoscamProtocol = 'http' | 'https';
export type TFoscamStream = typeof foscamStreams[number];
export type TFoscamPtzMovement = typeof foscamPtzMovements[number];
export type TFoscamEntityKey =
  | 'motion_detection'
  | 'is_flip'
  | 'is_mirror'
  | 'is_open_ir'
  | 'sleep_switch'
  | 'is_open_white_light'
  | 'is_siren_alarm'
  | 'is_turn_off_volume'
  | 'is_turn_off_light'
  | 'is_open_hdr'
  | 'is_open_wdr'
  | 'pet_detection'
  | 'car_detection'
  | 'human_detection'
  | 'device_volume'
  | 'speak_volume';
export type TFoscamCommandType =
  | 'refresh'
  | 'stream_source'
  | 'snapshot_image'
  | 'ptz'
  | 'ptz_preset'
  | 'set_switch'
  | 'set_number'
  | 'enable_motion_detection'
  | 'disable_motion_detection';

export interface IFoscamConfig {
  protocol?: TFoscamProtocol;
  host?: string;
  port?: number;
  url?: string;
  rtspPort?: number;
  username?: string;
  password?: string;
  stream?: TFoscamStream;
  timeoutMs?: number;
  snapshotTimeoutMs?: number;
  name?: string;
  uniqueId?: string;
  manufacturer?: string;
  model?: string;
  connected?: boolean;
  deviceInfo?: IFoscamDeviceInfo;
  camera?: Partial<IFoscamCamera>;
  switches?: IFoscamSwitch[];
  numbers?: IFoscamNumber[];
  currentSettings?: Partial<Record<TFoscamEntityKey, unknown>>;
  snapshot?: IFoscamSnapshot;
  client?: IFoscamClientLike;
  commandExecutor?: IFoscamCommandExecutor;
}

export interface IHomeAssistantFoscamConfig extends IFoscamConfig {}

export interface IFoscamDeviceInfo {
  id?: string;
  name?: string;
  manufacturer?: string;
  model?: string;
  productName?: string;
  serialNumber?: string;
  macAddress?: string;
  firmwareVersion?: string;
  hardwareVersion?: string;
  host?: string;
  port?: number;
  protocol?: TFoscamProtocol;
  rtspPort?: number;
  url?: string;
  online?: boolean;
  productInfo?: Record<string, unknown>;
  rawDevInfo?: Record<string, unknown>;
}

export interface IFoscamCamera {
  id: string;
  name?: string;
  stream: TFoscamStream;
  snapshotUrl?: string;
  rtspUrl?: string;
  streamSourceUrl?: string;
  available?: boolean;
  supportsPtz?: boolean;
  motionDetectionEnabled?: boolean;
  attributes?: Record<string, unknown>;
}

export interface IFoscamSwitch {
  key: Exclude<TFoscamEntityKey, 'device_volume' | 'speak_volume'>;
  name: string;
  isOn: boolean;
  available?: boolean;
  exists?: boolean;
  entityCategory?: string;
  deviceClass?: string;
  attributes?: Record<string, unknown>;
}

export interface IFoscamNumber {
  key: Extract<TFoscamEntityKey, 'device_volume' | 'speak_volume'>;
  name: string;
  value: number;
  min: number;
  max: number;
  step: number;
  available?: boolean;
  exists?: boolean;
  entityCategory?: string;
  unit?: string;
  attributes?: Record<string, unknown>;
}

export interface IFoscamSnapshot {
  deviceInfo: IFoscamDeviceInfo;
  camera: IFoscamCamera;
  switches: IFoscamSwitch[];
  numbers: IFoscamNumber[];
  currentSettings: Partial<Record<TFoscamEntityKey, unknown>>;
  connected: boolean;
  updatedAt?: string;
  source?: 'http' | 'snapshot' | 'client' | 'manual' | 'offline';
  error?: string;
  metadata?: Record<string, unknown>;
}

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

export interface IFoscamCommandRequest {
  type: TFoscamCommandType;
  service: string;
  target?: {
    entityId?: string;
    deviceId?: string;
  };
  data?: Record<string, unknown>;
  cameraId?: string;
  key?: TFoscamEntityKey;
  enabled?: boolean;
  value?: number;
  movement?: TFoscamPtzMovement;
  travelTime?: number;
  presetName?: string;
  filename?: string;
  httpCommands?: IFoscamHttpCommand[];
}

export interface IFoscamHttpCommand {
  label: string;
  method: 'GET';
  command: string;
  params?: Record<string, string | number | boolean>;
  expect?: 'ok' | 'image' | 'text';
}

export interface IFoscamCommandResponse {
  ok: boolean;
  label: string;
  method: 'GET';
  command: string;
  params?: Record<string, string | number | boolean>;
  result: number;
  data?: Record<string, string | undefined>;
}

export interface IFoscamRefreshResult {
  success: boolean;
  snapshot: IFoscamSnapshot;
  error?: string;
  data?: Record<string, unknown>;
}

export interface IFoscamClientLike {
  getSnapshot?(): Promise<IFoscamSnapshot | Record<string, unknown>>;
  getSnapshotImage?(): Promise<IFoscamSnapshotImage>;
  execute?(commandArg: IFoscamCommandRequest): Promise<unknown>;
  getProductAllInfo?(): Promise<Record<string, unknown>>;
  getDevInfo?(): Promise<Record<string, unknown>>;
}

export interface IFoscamCommandExecutor {
  execute(commandArg: IFoscamCommandRequest): Promise<unknown>;
}

export interface IFoscamManualEntry {
  host?: string;
  port?: number;
  url?: string;
  protocol?: TFoscamProtocol;
  username?: string;
  password?: string;
  stream?: TFoscamStream;
  rtspPort?: number;
  id?: string;
  name?: string;
  manufacturer?: string;
  model?: string;
  serialNumber?: string;
  macAddress?: string;
  metadata?: Record<string, unknown>;
}

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

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

export interface IFoscamSwitchDescription {
  key: IFoscamSwitch['key'];
  name: string;
  entityCategory?: string;
}

export interface IFoscamNumberDescription {
  key: IFoscamNumber['key'];
  name: string;
  min: number;
  max: number;
  step: number;
  entityCategory?: string;
}

export const foscamSwitchDescriptions: IFoscamSwitchDescription[] = [
  { key: 'motion_detection', name: 'Motion Detection' },
  { key: 'is_flip', name: 'Flip', entityCategory: 'config' },
  { key: 'is_mirror', name: 'Mirror', entityCategory: 'config' },
  { key: 'is_open_ir', name: 'Infrared Mode', entityCategory: 'config' },
  { key: 'sleep_switch', name: 'Sleep Mode', entityCategory: 'config' },
  { key: 'is_open_white_light', name: 'White Light', entityCategory: 'config' },
  { key: 'is_siren_alarm', name: 'Siren Alarm', entityCategory: 'config' },
  { key: 'is_turn_off_volume', name: 'Volume Muted', entityCategory: 'config' },
  { key: 'is_turn_off_light', name: 'Light', entityCategory: 'config' },
  { key: 'is_open_hdr', name: 'HDR', entityCategory: 'config' },
  { key: 'is_open_wdr', name: 'WDR', entityCategory: 'config' },
  { key: 'pet_detection', name: 'Pet Detection', entityCategory: 'config' },
  { key: 'car_detection', name: 'Car Detection', entityCategory: 'config' },
  { key: 'human_detection', name: 'Human Detection', entityCategory: 'config' },
];

export const foscamNumberDescriptions: IFoscamNumberDescription[] = [
  { key: 'device_volume', name: 'Device Volume', min: 0, max: 100, step: 1, entityCategory: 'config' },
  { key: 'speak_volume', name: 'Speak Volume', min: 0, max: 100, step: 1, entityCategory: 'config' },
];
