import type { IServiceCallResult } from '../../core/types.js';

export const opnsenseDomain = 'opnsense';
export const opnsenseDefaultPort = 443;
export const opnsenseDefaultVerifySsl = false;
export const opnsenseDefaultTimeoutMs = 10000;

export type TOpnsenseSnapshotSource = 'snapshot' | 'manual' | 'provider' | 'runtime';
export type TOpnsenseHttpMethod = 'GET' | 'POST';
export type TOpnsenseRouterAction = 'reboot' | 'halt' | 'firmware_update' | 'firmware_upgrade';
export type TOpnsenseServiceAction = 'start' | 'stop' | 'restart';
export type TOpnsenseToggleAction = 'toggle' | 'enable' | 'disable';
export type TOpnsenseInterfaceAction = 'reload';
export type TOpnsenseCommandType =
  | 'router.action'
  | 'service.action'
  | 'firewall.toggle'
  | 'nat.toggle'
  | 'alias.toggle'
  | 'vpn.toggle'
  | 'interface.reload'
  | 'notice.close'
  | 'wol.send'
  | 'firmware.action'
  | 'unbound.toggle'
  | 'speedtest.run'
  | 'switch.action';

export type TOpnsenseJsonValue = string | number | boolean | null | TOpnsenseJsonValue[] | {
  [key: string]: TOpnsenseJsonValue | undefined;
};

export interface IOpnsenseConfig {
  url?: string;
  host?: string;
  port?: number;
  ssl?: boolean;
  verifySsl?: boolean;
  verify_ssl?: boolean;
  apiKey?: string;
  api_key?: string;
  apiSecret?: string;
  api_secret?: string;
  timeoutMs?: number;
  trackerInterfaces?: string[];
  tracker_interfaces?: string[];
  connected?: boolean;
  uniqueId?: string;
  name?: string;
  snapshot?: IOpnsenseSnapshot;
  router?: IOpnsenseRouterInfo;
  devices?: IOpnsenseClientDevice[];
  clients?: IOpnsenseClientDevice[];
  arpTable?: IOpnsenseArpEntry[];
  interfaces?: IOpnsenseInterfaceInfo[];
  gateways?: IOpnsenseGatewayInfo[];
  firewall?: IOpnsenseFirewallSnapshot;
  system?: IOpnsenseSystemInfo;
  telemetry?: IOpnsenseTelemetryInfo;
  services?: IOpnsenseServiceInfo[];
  vpn?: IOpnsenseVpnSnapshot;
  vpns?: IOpnsenseVpnSnapshot;
  sensors?: IOpnsenseSensorMap;
  switches?: IOpnsenseSwitchInfo[];
  actions?: IOpnsenseActionDescriptor[];
  manualEntries?: IOpnsenseManualEntry[];
  events?: IOpnsenseEvent[];
  snapshotProvider?: TOpnsenseSnapshotProvider;
  commandExecutor?: TOpnsenseCommandExecutor;
  nativeClient?: IOpnsenseNativeClient;
  metadata?: Record<string, unknown>;
  [key: string]: unknown;
}

export interface IHomeAssistantOpnsenseConfig extends IOpnsenseConfig {}

export interface IOpnsenseRouterInfo {
  id?: string;
  url?: string;
  host?: string;
  port?: number;
  ssl?: boolean;
  verifySsl?: boolean;
  name?: string;
  model?: string;
  firmware?: string;
  productVersion?: string;
  latestFirmware?: string;
  updateAvailable?: boolean;
  serialNumber?: string;
  macAddress?: string;
  configurationUrl?: string;
  manufacturer?: string;
  actions?: TOpnsenseRouterAction[];
  metadata?: Record<string, unknown>;
}

export interface IOpnsenseClientDevice {
  id?: string;
  mac?: string;
  macAddress?: string;
  name?: string;
  hostname?: string | null;
  ip?: string;
  ipAddress?: string;
  address?: string;
  connected?: boolean;
  interface?: string;
  interfaceDescription?: string;
  intf_description?: string;
  manufacturer?: string;
  model?: string;
  lastActivity?: string | number | Date;
  expires?: string | number | Date;
  leaseType?: string;
  type?: string;
  metadata?: Record<string, unknown>;
  [key: string]: unknown;
}

export interface IOpnsenseArpEntry {
  mac?: string;
  macAddress?: string;
  'mac-address'?: string;
  ip?: string;
  ipAddress?: string;
  'ip-address'?: string;
  address?: string;
  hostname?: string;
  interface?: string;
  intf_description?: string;
  interfaceDescription?: string;
  manufacturer?: string;
  expires?: string | number;
  type?: string;
  [key: string]: unknown;
}

export interface IOpnsenseInterfaceInfo {
  id?: string;
  name: string;
  label?: string;
  description?: string;
  status?: string;
  enabled?: boolean | string | number;
  connected?: boolean;
  mac?: string;
  macAddress?: string;
  ipv4?: string | null;
  ipv6?: string | null;
  media?: string | null;
  device?: string | null;
  gateways?: string[];
  routes?: unknown[];
  vlanTag?: string | number | null;
  rxBytes?: number;
  txBytes?: number;
  inbytes?: number;
  outbytes?: number;
  rxPackets?: number;
  txPackets?: number;
  inpkts?: number;
  outpkts?: number;
  inputErrors?: number;
  outputErrors?: number;
  inerrs?: number;
  outerrs?: number;
  collisions?: number;
  actions?: TOpnsenseInterfaceAction[];
  metadata?: Record<string, unknown>;
  [key: string]: unknown;
}

export interface IOpnsenseGatewayInfo {
  id?: string;
  name: string;
  status?: string;
  address?: string;
  interface?: string;
  monitor?: string;
  delay?: number | string;
  rtt?: number | string;
  latency?: number | string;
  loss?: number | string;
  stddev?: number | string;
  disabled?: boolean | string | number;
  metadata?: Record<string, unknown>;
  [key: string]: unknown;
}

export interface IOpnsenseFirewallRule {
  id?: string;
  uuid?: string;
  description?: string;
  descr?: string;
  enabled?: boolean | string | number;
  disabled?: boolean | string | number;
  interface?: string;
  direction?: string;
  protocol?: string;
  action?: string;
  source?: unknown;
  destination?: unknown;
  metadata?: Record<string, unknown>;
  [key: string]: unknown;
}

export interface IOpnsenseFirewallAlias {
  id?: string;
  uuid?: string;
  name: string;
  description?: string;
  enabled?: boolean | string | number;
  disabled?: boolean | string | number;
  type?: string;
  content?: unknown;
  metadata?: Record<string, unknown>;
  [key: string]: unknown;
}

export interface IOpnsenseFirewallSnapshot {
  rules?: IOpnsenseFirewallRule[] | Record<string, IOpnsenseFirewallRule>;
  nat?: Record<string, IOpnsenseFirewallRule[] | Record<string, IOpnsenseFirewallRule> | undefined>;
  aliases?: IOpnsenseFirewallAlias[] | Record<string, IOpnsenseFirewallAlias>;
  state?: {
    used?: number;
    total?: number;
    usedPercent?: number;
    used_percent?: number;
    [key: string]: unknown;
  };
  metadata?: Record<string, unknown>;
  [key: string]: unknown;
}

export interface IOpnsenseSystemInfo {
  name?: string;
  hostname?: string;
  firmwareVersion?: string;
  productVersion?: string;
  productLatest?: string;
  updateAvailable?: boolean;
  uptime?: number;
  boottime?: string | number | Date;
  loadAverage?: {
    oneMinute?: number;
    fiveMinute?: number;
    fifteenMinute?: number;
    one_minute?: number;
    five_minute?: number;
    fifteen_minute?: number;
  };
  pendingNoticesPresent?: boolean;
  pending_notices_present?: boolean;
  pendingNotices?: IOpnsenseNotice[];
  pending_notices?: IOpnsenseNotice[];
  carp?: Record<string, unknown>;
  certificates?: Record<string, unknown>;
  speedtest?: Record<string, unknown>;
  metadata?: Record<string, unknown>;
  [key: string]: unknown;
}

export interface IOpnsenseNotice {
  id?: string;
  notice?: string;
  createdAt?: string | number | Date;
  created_at?: string | number | Date;
  [key: string]: unknown;
}

export interface IOpnsenseTelemetryInfo {
  cpu?: Record<string, unknown>;
  memory?: Record<string, unknown>;
  mbuf?: Record<string, unknown>;
  pfstate?: Record<string, unknown>;
  system?: Record<string, unknown>;
  filesystems?: Array<Record<string, unknown>>;
  temps?: Record<string, Record<string, unknown>>;
  vnstat?: Record<string, unknown>;
  speedtest?: Record<string, unknown>;
  metadata?: Record<string, unknown>;
  [key: string]: unknown;
}

export interface IOpnsenseServiceInfo {
  id?: string;
  name: string;
  displayName?: string;
  description?: string;
  running?: boolean | string | number;
  status?: boolean | string | number;
  enabled?: boolean | string | number;
  locked?: boolean | string | number;
  actions?: TOpnsenseServiceAction[];
  metadata?: Record<string, unknown>;
  [key: string]: unknown;
}

export interface IOpnsenseVpnSnapshot {
  openvpn?: {
    servers?: IOpnsenseVpnInstance[] | Record<string, IOpnsenseVpnInstance>;
    clients?: IOpnsenseVpnInstance[] | Record<string, IOpnsenseVpnInstance>;
    [key: string]: unknown;
  };
  wireguard?: {
    servers?: IOpnsenseVpnInstance[] | Record<string, IOpnsenseVpnInstance>;
    clients?: IOpnsenseVpnInstance[] | Record<string, IOpnsenseVpnInstance>;
    [key: string]: unknown;
  };
  metadata?: Record<string, unknown>;
  [key: string]: unknown;
}

export interface IOpnsenseVpnInstance {
  id?: string;
  uuid?: string;
  name?: string;
  description?: string;
  type?: 'openvpn' | 'wireguard' | string;
  role?: 'server' | 'client' | string;
  enabled?: boolean | string | number;
  status?: string;
  connected?: boolean;
  interface?: string;
  endpoint?: string;
  connectedClients?: number;
  connected_clients?: number;
  connectedServers?: number;
  connected_servers?: number;
  totalBytesRecv?: number;
  total_bytes_recv?: number;
  totalBytesSent?: number;
  total_bytes_sent?: number;
  latestHandshake?: string | number | Date;
  latest_handshake?: string | number | Date;
  clients?: Array<Record<string, unknown>>;
  servers?: Array<Record<string, unknown>>;
  metadata?: Record<string, unknown>;
  [key: string]: unknown;
}

export interface IOpnsenseSensorMap {
  connected_clients?: number;
  pending_notices?: boolean;
  cpu_usage?: number;
  memory_usage?: number;
  pf_state_used?: number;
  pf_state_used_percent?: number;
  mbuf_used_percent?: number;
  uptime?: number;
  [key: string]: string | number | boolean | Date | null | undefined;
}

export interface IOpnsenseSwitchInfo {
  id?: string;
  name: string;
  enabled?: boolean | string | number;
  available?: boolean;
  nativeType?: string;
  action?: string;
  uuid?: string;
  service?: string;
  path?: string;
  method?: TOpnsenseHttpMethod;
  payload?: Record<string, unknown>;
  metadata?: Record<string, unknown>;
  [key: string]: unknown;
}

export interface IOpnsenseActionDescriptor {
  target: 'router' | 'interface' | 'service' | 'firewall_rule' | 'nat_rule' | 'firewall_alias' | 'vpn' | 'switch' | 'firmware' | 'notice' | 'wol' | 'unbound' | 'speedtest';
  action: string;
  id?: string | number;
  uuid?: string;
  service?: string;
  interface?: string;
  mac?: string;
  vpnType?: 'openvpn' | 'wireguard' | string;
  vpnRole?: 'server' | 'client' | string;
  natRuleType?: string;
  entityId?: string;
  deviceId?: string;
  path?: string;
  method?: TOpnsenseHttpMethod;
  payload?: Record<string, unknown>;
  label?: string;
  metadata?: Record<string, unknown>;
}

export interface IOpnsenseSnapshot {
  connected: boolean;
  source?: TOpnsenseSnapshotSource;
  updatedAt?: string;
  router: IOpnsenseRouterInfo;
  devices: IOpnsenseClientDevice[];
  interfaces: IOpnsenseInterfaceInfo[];
  gateways: IOpnsenseGatewayInfo[];
  firewall: IOpnsenseFirewallSnapshot;
  system: IOpnsenseSystemInfo;
  telemetry: IOpnsenseTelemetryInfo;
  services: IOpnsenseServiceInfo[];
  vpn: IOpnsenseVpnSnapshot;
  sensors: IOpnsenseSensorMap;
  switches: IOpnsenseSwitchInfo[];
  actions?: IOpnsenseActionDescriptor[];
  events?: IOpnsenseEvent[];
  error?: string;
  metadata?: Record<string, unknown>;
}

export interface IOpnsenseManualEntry {
  id?: string;
  url?: string;
  host?: string;
  port?: number;
  ssl?: boolean;
  verifySsl?: boolean;
  apiKey?: string;
  apiSecret?: string;
  trackerInterfaces?: string[];
  name?: string;
  manufacturer?: string;
  model?: string;
  macAddress?: string;
  snapshot?: IOpnsenseSnapshot;
  router?: IOpnsenseRouterInfo;
  devices?: IOpnsenseClientDevice[];
  clients?: IOpnsenseClientDevice[];
  arpTable?: IOpnsenseArpEntry[];
  interfaces?: IOpnsenseInterfaceInfo[];
  gateways?: IOpnsenseGatewayInfo[];
  firewall?: IOpnsenseFirewallSnapshot;
  system?: IOpnsenseSystemInfo;
  telemetry?: IOpnsenseTelemetryInfo;
  services?: IOpnsenseServiceInfo[];
  vpn?: IOpnsenseVpnSnapshot;
  vpns?: IOpnsenseVpnSnapshot;
  sensors?: IOpnsenseSensorMap;
  switches?: IOpnsenseSwitchInfo[];
  actions?: IOpnsenseActionDescriptor[];
  metadata?: Record<string, unknown>;
  integrationDomain?: string;
  [key: string]: unknown;
}

export interface IOpnsenseManualDiscoveryRecord extends IOpnsenseManualEntry {}

export interface IOpnsenseCommand {
  type: TOpnsenseCommandType;
  service: string;
  action: string;
  target: {
    entityId?: string;
    deviceId?: string;
  };
  method?: TOpnsenseHttpMethod;
  path?: string;
  payload?: Record<string, unknown>;
  routerId?: string;
  entityId?: string;
  deviceId?: string;
  uuid?: string;
  serviceName?: string;
  interface?: string;
  mac?: string;
  vpnType?: string;
  vpnRole?: string;
  natRuleType?: string;
}

export interface IOpnsenseCommandResult extends IServiceCallResult {}

export interface IOpnsenseEvent {
  type: string;
  timestamp?: number;
  deviceId?: string;
  entityId?: string;
  command?: IOpnsenseCommand;
  snapshot?: IOpnsenseSnapshot;
  error?: string;
  data?: unknown;
  [key: string]: unknown;
}

export interface IOpnsenseNativeClient {
  getSnapshot(): Promise<IOpnsenseSnapshot> | IOpnsenseSnapshot;
  executeCommand?(commandArg: IOpnsenseCommand): Promise<IOpnsenseCommandResult | unknown> | IOpnsenseCommandResult | unknown;
  destroy?(): Promise<void> | void;
}

export type TOpnsenseSnapshotProvider = () => Promise<IOpnsenseSnapshot | undefined> | IOpnsenseSnapshot | undefined;
export type TOpnsenseCommandExecutor = (
  commandArg: IOpnsenseCommand
) => Promise<IOpnsenseCommandResult | unknown> | IOpnsenseCommandResult | unknown;
