import * as plugins from '../plugins.js';

export type TDiscoverySource =
  | 'mdns'
  | 'ssdp'
  | 'dhcp'
  | 'bluetooth'
  | 'usb'
  | 'mqtt'
  | 'http'
  | 'manual'
  | 'broker'
  | 'cloud'
  | 'custom';

export type TDiscoveryConfidence = 'low' | 'medium' | 'high' | 'certain';

export type TIntegrationStatus =
  | 'descriptor-only'
  | 'discovery-supported'
  | 'config-flow-supported'
  | 'read-only-runtime'
  | 'control-runtime'
  | 'production-ready';

export interface ILogger {
  log(levelArg: 'debug' | 'info' | 'warn' | 'error', messageArg: string, metadataArg?: Record<string, unknown>): void;
}

export interface INetworkInterface {
  name: string;
  address: string;
  family: 'IPv4' | 'IPv6';
  internal: boolean;
}

export interface IConfigStore {
  get<TValue>(keyArg: string): Promise<TValue | undefined>;
  set<TValue>(keyArg: string, valueArg: TValue): Promise<void>;
  delete(keyArg: string): Promise<void>;
  list(prefixArg?: string): Promise<string[]>;
}

export interface IDiscoveryContext {
  abortSignal?: AbortSignal;
  logger?: ILogger;
  networkInterfaces?: INetworkInterface[];
  configStore?: IConfigStore;
}

export interface IDiscoveryCandidate {
  source: TDiscoverySource;
  integrationDomain?: string;
  id?: string;
  host?: string;
  port?: number;
  name?: string;
  manufacturer?: string;
  model?: string;
  serialNumber?: string;
  macAddress?: string;
  metadata?: Record<string, unknown>;
}

export interface IDiscoveryProbeResult {
  candidates: IDiscoveryCandidate[];
}

export interface IDiscoveryMatch {
  matched: boolean;
  confidence: TDiscoveryConfidence;
  reason: string;
  candidate?: IDiscoveryCandidate;
  normalizedDeviceId?: string;
  metadata?: Record<string, unknown>;
}

export interface IDiscoveryProbe {
  id: string;
  source: TDiscoverySource;
  description?: string;
  probe(contextArg: IDiscoveryContext): Promise<IDiscoveryProbeResult>;
}

export interface IDiscoveryMatcher<TInput = unknown> {
  id: string;
  source: TDiscoverySource;
  description?: string;
  matches(inputArg: TInput, contextArg: IDiscoveryContext): Promise<IDiscoveryMatch>;
}

export interface IDiscoveryValidator {
  id: string;
  description?: string;
  validate(candidateArg: IDiscoveryCandidate, contextArg: IDiscoveryContext): Promise<IDiscoveryMatch>;
}

export interface IDiscoveryDescriptorOptions {
  integrationDomain: string;
  displayName: string;
}

export interface IIntegrationSetupContext {
  logger?: ILogger;
  configStore?: IConfigStore;
  abortSignal?: AbortSignal;
}

export type TEntityPlatform =
  | 'light'
  | 'switch'
  | 'sensor'
  | 'binary_sensor'
  | 'button'
  | 'camera'
  | 'climate'
  | 'cover'
  | 'fan'
  | 'media_player'
  | 'number'
  | 'select'
  | 'text'
  | 'update';

export interface IIntegrationEntity<TState = unknown> {
  id: string;
  uniqueId: string;
  integrationDomain: string;
  deviceId: string;
  platform: TEntityPlatform;
  name: string;
  state: TState;
  attributes?: Record<string, unknown>;
  available: boolean;
}

export interface IServiceCallRequest {
  domain: string;
  service: string;
  target: {
    entityId?: string;
    deviceId?: string;
  };
  data?: Record<string, unknown>;
}

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

export type TIntegrationEventType =
  | 'device_added'
  | 'device_removed'
  | 'entity_added'
  | 'entity_removed'
  | 'state_changed'
  | 'availability_changed'
  | 'error';

export interface IIntegrationEvent {
  type: TIntegrationEventType;
  integrationDomain: string;
  deviceId?: string;
  entityId?: string;
  data?: unknown;
  timestamp: number;
}

export interface IIntegrationRuntime {
  domain: string;
  devices(): Promise<plugins.shxInterfaces.data.IDeviceDefinition[]>;
  entities(): Promise<IIntegrationEntity[]>;
  subscribe?(handlerArg: (eventArg: IIntegrationEvent) => void): Promise<() => Promise<void>>;
  callService?(requestArg: IServiceCallRequest): Promise<IServiceCallResult>;
  destroy(): Promise<void>;
}

export type TConfigFlowStepKind = 'form' | 'wait' | 'done' | 'error';

export interface IConfigFlowField {
  name: string;
  label: string;
  type: 'text' | 'password' | 'number' | 'boolean' | 'select';
  required?: boolean;
  options?: Array<{
    label: string;
    value: string;
  }>;
}

export interface IConfigFlowContext {
  logger?: ILogger;
  configStore?: IConfigStore;
}

export interface IConfigFlowStep<TConfig = unknown> {
  kind: TConfigFlowStepKind;
  title?: string;
  description?: string;
  fields?: IConfigFlowField[];
  submit?(valuesArg: Record<string, unknown>): Promise<IConfigFlowStep<TConfig>>;
  config?: TConfig;
  error?: string;
}

export interface IConfigFlow<TConfig = unknown> {
  start(candidateArg: IDiscoveryCandidate, contextArg: IConfigFlowContext): Promise<IConfigFlowStep<TConfig>>;
}
