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

export const fritzboxCallmonitorDomain = 'fritzbox_callmonitor';
export const fritzboxCallmonitorDefaultHost = '169.254.1.1';
export const fritzboxCallmonitorDefaultPort = 1012;
export const fritzboxCallmonitorDefaultName = 'Phone';
export const fritzboxCallmonitorManufacturer = 'FRITZ!';

export type TFritzboxCallmonitorFritzState = 'RING' | 'CALL' | 'CONNECT' | 'DISCONNECT';
export type TFritzboxCallmonitorCallState = 'ringing' | 'dialing' | 'talking' | 'idle';
export type TFritzboxCallmonitorDirection = 'incoming' | 'outgoing' | 'connected' | 'disconnected' | 'unknown';
export type TFritzboxCallmonitorSnapshotSource = 'snapshot' | 'manual' | 'provider' | 'tcp' | 'runtime';
export type TFritzboxCallmonitorClientEventType =
  | 'snapshot_refreshed'
  | 'event_received'
  | 'event_parse_failed'
  | 'monitor_started'
  | 'monitor_stopped'
  | 'monitor_failed';
export type TFritzboxCallmonitorEventInput = string | IFritzboxCallmonitorCallEvent;

export interface IFritzboxCallmonitorConfig {
  host?: string;
  port?: number;
  username?: string;
  password?: string;
  phonebookId?: number;
  phonebookName?: string;
  prefixes?: string[];
  contacts?: IFritzboxCallmonitorContactInput[];
  serialNumber?: string;
  uniqueId?: string;
  name?: string;
  model?: string;
  connected?: boolean;
  snapshot?: IFritzboxCallmonitorSnapshot;
  events?: TFritzboxCallmonitorEventInput[];
  eventLines?: string[];
  snapshotProvider?: TFritzboxCallmonitorSnapshotProvider;
  nativeClient?: IFritzboxCallmonitorNativeClient;
  eventSource?: IFritzboxCallmonitorEventSource;
  eventExecutor?: TFritzboxCallmonitorEventExecutor;
  timeoutMs?: number;
  metadata?: Record<string, unknown>;
  [key: string]: unknown;
}

export interface IHomeAssistantFritzboxCallmonitorConfig extends IFritzboxCallmonitorConfig {}

export interface IFritzboxCallmonitorMonitorInfo {
  id?: string;
  host?: string;
  port?: number;
  name?: string;
  phonebookName?: string;
  phonebookId?: number;
  username?: string;
  serialNumber?: string;
  manufacturer?: string;
  model?: string;
  configurationUrl?: string;
  metadata?: Record<string, unknown>;
}

export interface IFritzboxCallmonitorContactInput {
  name?: string;
  number?: string;
  numbers?: string[];
  vip?: boolean;
  category?: string;
  [key: string]: unknown;
}

export interface IFritzboxCallmonitorContact {
  name: string;
  numbers: string[];
  vip: boolean;
  category?: string;
}

export interface IFritzboxCallmonitorCallAttributes {
  type?: 'incoming' | 'outgoing';
  from?: string;
  to?: string;
  device?: string;
  initiated?: string;
  from_name?: string;
  to_name?: string;
  with?: string;
  with_name?: string;
  accepted?: string;
  duration?: string;
  closed?: string;
  vip?: boolean;
  [key: string]: string | boolean | string[] | undefined;
}

export interface IFritzboxCallmonitorCallEvent {
  type: 'call_event';
  raw?: string;
  line?: string[];
  fritzState: TFritzboxCallmonitorFritzState;
  callState: TFritzboxCallmonitorCallState;
  direction: TFritzboxCallmonitorDirection;
  callId?: string;
  timestamp?: string;
  attributes: IFritzboxCallmonitorCallAttributes;
}

export interface IFritzboxCallmonitorCallSnapshot {
  state: TFritzboxCallmonitorCallState;
  attributes: IFritzboxCallmonitorCallAttributes;
  lastEvent?: IFritzboxCallmonitorCallEvent;
}

export interface IFritzboxCallmonitorSnapshot {
  connected: boolean;
  source?: TFritzboxCallmonitorSnapshotSource;
  updatedAt?: string;
  monitor: IFritzboxCallmonitorMonitorInfo;
  call: IFritzboxCallmonitorCallSnapshot;
  contacts: IFritzboxCallmonitorContact[];
  prefixes?: string[];
  events: IFritzboxCallmonitorCallEvent[];
  error?: string;
  metadata?: Record<string, unknown>;
}

export interface IFritzboxCallmonitorClientEvent {
  type: TFritzboxCallmonitorClientEventType;
  timestamp: number;
  snapshot?: IFritzboxCallmonitorSnapshot;
  callEvent?: IFritzboxCallmonitorCallEvent;
  raw?: string;
  error?: string;
  data?: unknown;
}

export interface IFritzboxCallmonitorNativeClient {
  getSnapshot?(): Promise<IFritzboxCallmonitorSnapshot> | IFritzboxCallmonitorSnapshot;
  subscribe?(handlerArg: (eventArg: TFritzboxCallmonitorEventInput) => void): Promise<TFritzboxCallmonitorUnsubscribe | void> | TFritzboxCallmonitorUnsubscribe | void;
  destroy?(): Promise<void> | void;
}

export interface IFritzboxCallmonitorEventSource {
  subscribe(handlerArg: (eventArg: TFritzboxCallmonitorEventInput) => void): Promise<TFritzboxCallmonitorUnsubscribe | void> | TFritzboxCallmonitorUnsubscribe | void;
}

export interface IFritzboxCallmonitorEventExecutorRequest {
  host?: string;
  port: number;
  onLine(lineArg: string): void;
  onError(errorArg: Error): void;
}

export interface IFritzboxCallmonitorEventStream {
  stop?(): Promise<void> | void;
}

export type TFritzboxCallmonitorUnsubscribe = () => Promise<void> | void;
export type TFritzboxCallmonitorSnapshotProvider = () => Promise<IFritzboxCallmonitorSnapshot | undefined> | IFritzboxCallmonitorSnapshot | undefined;
export type TFritzboxCallmonitorEventExecutor = (
  requestArg: IFritzboxCallmonitorEventExecutorRequest
) => Promise<IFritzboxCallmonitorEventStream | IServiceCallResult | void> | IFritzboxCallmonitorEventStream | IServiceCallResult | void;

export interface IFritzboxCallmonitorManualDiscoveryRecord extends IFritzboxCallmonitorConfig {
  source?: string;
  integrationDomain?: string;
  id?: string;
  manufacturer?: string;
  macAddress?: string;
}

export interface IFritzboxCallmonitorSsdpDiscoveryRecord {
  source?: string;
  integrationDomain?: string;
  id?: string;
  host?: string;
  port?: number;
  name?: string;
  manufacturer?: string;
  model?: string;
  serialNumber?: string;
  macAddress?: string;
  ssdpLocation?: string;
  ssdp_location?: string;
  location?: string;
  st?: string;
  usn?: string;
  udn?: string;
  upnp?: Record<string, unknown>;
  metadata?: Record<string, unknown>;
  [key: string]: unknown;
}

export interface IFritzboxCallmonitorMdnsDiscoveryRecord {
  source?: string;
  integrationDomain?: string;
  id?: string;
  host?: string;
  port?: number;
  name?: string;
  manufacturer?: string;
  model?: string;
  serialNumber?: string;
  macAddress?: string;
  serviceType?: string;
  type?: string;
  fullname?: string;
  metadata?: Record<string, unknown>;
  [key: string]: unknown;
}
