import * as plugins from '../../plugins.js';
import type { IIntegrationEntity, IServiceCallRequest, TEntityPlatform } from '../../core/types.js';
import type {
  IDoorbirdButtonSnapshot,
  IDoorbirdCameraSnapshot,
  IDoorbirdCommandRequest,
  IDoorbirdConfig,
  IDoorbirdDeviceInfo,
  IDoorbirdEventSnapshot,
  IDoorbirdFavoriteChange,
  IDoorbirdInfo,
  IDoorbirdRawData,
  IDoorbirdSnapshot,
  IDoorbirdStatus,
  TDoorbirdCameraKind,
  TDoorbirdProtocol,
  TDoorbirdSnapshotSource,
} from './doorbird.types.js';
import {
  doorbirdDefaultHttpsPort,
  doorbirdDefaultPort,
  doorbirdDefaultRtspPort,
  doorbirdDomain,
  doorbirdManufacturer,
} from './doorbird.types.js';

interface IDoorbirdSnapshotOptions {
  config: IDoorbirdConfig;
  rawData?: Partial<IDoorbirdRawData>;
  online?: boolean;
  source?: TDoorbirdSnapshotSource;
  error?: string;
}

interface IDoorbirdEntityDefinition {
  key: string;
  platform: TEntityPlatform;
  name: string;
  state: unknown;
  available: boolean;
  attributes?: Record<string, unknown>;
}

const cameraSnapshotServices = new Set(['snapshot', 'camera_image', 'camera_snapshot']);
const cameraStreamServices = new Set(['stream', 'stream_source', 'get_stream']);

export class DoorbirdMapper {
  public static toSnapshot(optionsArg: IDoorbirdSnapshotOptions): IDoorbirdSnapshot {
    if (optionsArg.config.snapshot && !optionsArg.rawData) {
      return this.normalizeSnapshot(this.clone(optionsArg.config.snapshot), optionsArg.config, optionsArg.source || 'snapshot');
    }

    const rawData = this.rawData(optionsArg.config, optionsArg.rawData);
    const online = optionsArg.online ?? optionsArg.config.online ?? this.hasRawData(rawData);
    const updatedAt = new Date().toISOString();
    const deviceInfo = this.deviceInfo(optionsArg.config, rawData.info, online);
    const snapshot: IDoorbirdSnapshot = {
      deviceInfo,
      cameras: this.cameras(optionsArg.config, deviceInfo, online),
      buttons: this.buttons(optionsArg.config, deviceInfo, online),
      events: this.events(optionsArg.config, deviceInfo, online),
      status: this.status(rawData.status),
      rawInfo: rawData.info,
      favorites: rawData.favorites,
      schedule: rawData.schedule,
      online,
      updatedAt,
      source: optionsArg.source || (this.hasRawData(rawData) ? 'manual' : 'runtime'),
      error: optionsArg.error,
    };
    return this.normalizeSnapshot(snapshot, optionsArg.config, snapshot.source || 'runtime');
  }

  public static toDevices(snapshotArg: IDoorbirdSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
    const updatedAt = snapshotArg.updatedAt || new Date().toISOString();
    const features: plugins.shxInterfaces.data.IDeviceFeature[] = [
      { id: 'connection', capability: 'sensor', name: 'Connection', readable: true, writable: false },
      { id: 'doorbell', capability: 'sensor', name: 'Doorbell', readable: true, writable: false },
      { id: 'motion', capability: 'sensor', name: 'Motion', readable: true, writable: false },
    ];
    const state: plugins.shxInterfaces.data.IDeviceState[] = [
      { featureId: 'connection', value: snapshotArg.online ? 'online' : 'offline', updatedAt },
      { featureId: 'doorbell', value: snapshotArg.status.doorbell ?? null, updatedAt },
      { featureId: 'motion', value: snapshotArg.status.motion ?? null, updatedAt },
    ];

    for (const camera of snapshotArg.cameras) {
      features.push({ id: `camera_${this.slug(camera.id)}`, capability: 'camera', name: camera.name, readable: true, writable: false });
      state.push({
        featureId: `camera_${this.slug(camera.id)}`,
        value: {
          stillImageUrl: camera.stillImageUrl || null,
          liveVideoUrl: camera.liveVideoUrl || null,
          rtspUrl: camera.rtspUrl || null,
        },
        updatedAt,
      });
    }
    for (const button of snapshotArg.buttons) {
      features.push({ id: `button_${this.slug(button.key)}`, capability: 'switch', name: button.name, readable: false, writable: true });
    }

    return [{
      id: this.deviceId(snapshotArg),
      integrationDomain: doorbirdDomain,
      name: this.deviceName(snapshotArg),
      protocol: 'http',
      manufacturer: snapshotArg.deviceInfo.manufacturer || doorbirdManufacturer,
      model: snapshotArg.deviceInfo.model || 'DoorBird door station',
      online: snapshotArg.online,
      features,
      state,
      metadata: this.cleanAttributes({
        macAddress: snapshotArg.deviceInfo.macAddress,
        primaryMacAddress: snapshotArg.deviceInfo.primaryMacAddress,
        wifiMacAddress: snapshotArg.deviceInfo.wifiMacAddress,
        firmware: snapshotArg.deviceInfo.firmware,
        buildNumber: snapshotArg.deviceInfo.buildNumber,
        swVersion: snapshotArg.deviceInfo.swVersion,
        host: snapshotArg.deviceInfo.host,
        port: snapshotArg.deviceInfo.port,
        baseUrl: snapshotArg.deviceInfo.baseUrl,
        html5ViewerUrl: snapshotArg.deviceInfo.html5ViewerUrl,
        rtspUrl: snapshotArg.deviceInfo.rtspUrl,
        relays: snapshotArg.deviceInfo.relays,
        source: snapshotArg.source,
        error: snapshotArg.error,
      }),
    }];
  }

  public static toEntities(snapshotArg: IDoorbirdSnapshot): IIntegrationEntity[] {
    const deviceId = this.deviceId(snapshotArg);
    const uniqueBase = this.uniqueBase(snapshotArg);
    const baseName = this.deviceName(snapshotArg);
    const usedIds = new Map<string, number>();
    const entities: IIntegrationEntity[] = [];

    entities.push(this.entity(snapshotArg, usedIds, deviceId, uniqueBase, {
      key: 'online',
      platform: 'binary_sensor',
      name: `${baseName} Online`,
      state: snapshotArg.online ? 'on' : 'off',
      available: true,
      attributes: { deviceClass: 'connectivity', source: snapshotArg.source, error: snapshotArg.error },
    }));
    entities.push(this.entity(snapshotArg, usedIds, deviceId, uniqueBase, {
      key: 'doorbell',
      platform: 'binary_sensor',
      name: `${baseName} Doorbell`,
      state: snapshotArg.status.doorbell ? 'on' : 'off',
      available: snapshotArg.online && snapshotArg.status.doorbell !== undefined,
      attributes: { deviceClass: 'occupancy', raw: snapshotArg.status.rawDoorbell },
    }));
    entities.push(this.entity(snapshotArg, usedIds, deviceId, uniqueBase, {
      key: 'motion',
      platform: 'binary_sensor',
      name: `${baseName} Motion`,
      state: snapshotArg.status.motion ? 'on' : 'off',
      available: snapshotArg.online && snapshotArg.status.motion !== undefined,
      attributes: { deviceClass: 'motion', raw: snapshotArg.status.rawMotion },
    }));

    for (const camera of snapshotArg.cameras) {
      entities.push(this.entity(snapshotArg, usedIds, deviceId, uniqueBase, {
        key: `camera_${camera.id}`,
        platform: 'camera' as TEntityPlatform,
        name: `${baseName} ${camera.name}`,
        state: camera.available === false || !snapshotArg.online ? 'unavailable' : 'idle',
        available: snapshotArg.online && camera.available !== false,
        attributes: this.cleanAttributes({
          cameraId: camera.id,
          kind: camera.kind,
          stillImageUrl: camera.stillImageUrl,
          liveVideoUrl: camera.liveVideoUrl,
          streamSourceUrl: camera.liveVideoUrl || camera.rtspUrl || camera.stillImageUrl,
          rtspUrl: camera.rtspUrl,
          historyEvent: camera.historyEvent,
          historyIndex: camera.historyIndex,
          supportedFeatures: camera.id === 'live' ? ['snapshot', 'stream'] : ['snapshot'],
          requiresAuth: true,
        }),
      }));
    }

    for (const button of snapshotArg.buttons) {
      entities.push(this.entity(snapshotArg, usedIds, deviceId, uniqueBase, {
        key: button.key,
        platform: 'button',
        name: `${baseName} ${button.name}`,
        state: 'idle',
        available: snapshotArg.online && button.available !== false,
        attributes: this.cleanAttributes({
          action: button.action,
          relay: button.relay,
          entityCategory: button.entityCategory,
        }),
      }));
    }

    for (const event of snapshotArg.events) {
      entities.push(this.entity(snapshotArg, usedIds, deviceId, uniqueBase, {
        key: `event_${event.key}`,
        platform: 'event' as TEntityPlatform,
        name: `${baseName} ${event.name}`,
        state: 'idle',
        available: snapshotArg.online && event.available !== false,
        attributes: {
          eventType: event.eventType,
          doorbirdEvent: event.doorbirdEvent,
          eventTypes: [event.eventType === 'motion' ? 'motion' : 'ring'],
        },
      }));
    }

    return entities;
  }

  public static commandForService(snapshotArg: IDoorbirdSnapshot, requestArg: IServiceCallRequest): IDoorbirdCommandRequest | undefined {
    if (requestArg.domain === 'camera' && cameraSnapshotServices.has(requestArg.service)) {
      return { action: 'snapshot_image', service: requestArg.service, target: requestArg.target, data: requestArg.data, cameraId: this.cameraIdFromRequest(snapshotArg, requestArg) };
    }
    if (requestArg.domain === 'camera' && cameraStreamServices.has(requestArg.service)) {
      return { action: 'stream_source', service: requestArg.service, target: requestArg.target, data: requestArg.data, cameraId: this.cameraIdFromRequest(snapshotArg, requestArg) };
    }
    if (requestArg.domain === 'button' && requestArg.service === 'press') {
      const button = this.buttonFromRequest(snapshotArg, requestArg);
      if (!button) {
        return undefined;
      }
      return this.commandFromButton(button, requestArg);
    }
    if (requestArg.domain !== doorbirdDomain) {
      return undefined;
    }

    if (requestArg.service === 'refresh') {
      return { action: 'refresh', service: requestArg.service, target: requestArg.target, data: requestArg.data };
    }
    if (requestArg.service === 'snapshot' || cameraSnapshotServices.has(requestArg.service)) {
      return { action: 'snapshot_image', service: requestArg.service, target: requestArg.target, data: requestArg.data, cameraId: this.cameraIdFromRequest(snapshotArg, requestArg) };
    }
    if (requestArg.service === 'stream_source' || cameraStreamServices.has(requestArg.service)) {
      return { action: 'stream_source', service: requestArg.service, target: requestArg.target, data: requestArg.data, cameraId: this.cameraIdFromRequest(snapshotArg, requestArg) };
    }
    if (['energize_relay', 'open_door', 'relay', 'press_relay'].includes(requestArg.service)) {
      return { action: 'energize_relay', service: requestArg.service, target: requestArg.target, data: requestArg.data, relay: this.relayFromRequest(snapshotArg, requestArg) || '1' };
    }
    if (requestArg.service === 'turn_light_on' || requestArg.service === 'light_on') {
      return { action: 'turn_light_on', service: requestArg.service, target: requestArg.target, data: requestArg.data };
    }
    if (requestArg.service === 'doorbell_state') {
      return { action: 'doorbell_state', service: requestArg.service, target: requestArg.target, data: requestArg.data };
    }
    if (requestArg.service === 'motion_sensor_state') {
      return { action: 'motion_sensor_state', service: requestArg.service, target: requestArg.target, data: requestArg.data };
    }
    if (requestArg.service === 'favorites') {
      return { action: 'favorites', service: requestArg.service, target: requestArg.target, data: requestArg.data };
    }
    if (requestArg.service === 'change_favorite') {
      const favorite = this.favoriteChangeFromData(requestArg.data);
      return favorite ? { action: 'change_favorite', service: requestArg.service, target: requestArg.target, data: requestArg.data, favorite } : undefined;
    }
    if (requestArg.service === 'delete_favorite') {
      const favoriteType = this.stringValue(requestArg.data?.type ?? requestArg.data?.favoriteType);
      const favoriteId = this.stringValue(requestArg.data?.id ?? requestArg.data?.favoriteId);
      return favoriteType && favoriteId ? { action: 'delete_favorite', service: requestArg.service, target: requestArg.target, data: requestArg.data, favoriteType, favoriteId } : undefined;
    }
    if (requestArg.service === 'schedule') {
      return { action: 'schedule', service: requestArg.service, target: requestArg.target, data: requestArg.data };
    }
    if (requestArg.service === 'change_schedule') {
      const scheduleEntry = requestArg.data?.scheduleEntry || requestArg.data?.entry;
      return scheduleEntry && typeof scheduleEntry === 'object' && !Array.isArray(scheduleEntry)
        ? { action: 'change_schedule', service: requestArg.service, target: requestArg.target, data: requestArg.data, scheduleEntry: scheduleEntry as IDoorbirdCommandRequest['scheduleEntry'] }
        : undefined;
    }
    if (requestArg.service === 'delete_schedule') {
      const scheduleInput = this.stringValue(requestArg.data?.input ?? requestArg.data?.event);
      return scheduleInput ? { action: 'delete_schedule', service: requestArg.service, target: requestArg.target, data: requestArg.data, scheduleInput, scheduleParam: this.stringValue(requestArg.data?.param) } : undefined;
    }
    if (requestArg.service === 'reset_favorites') {
      return { action: 'reset_favorites', service: requestArg.service, target: requestArg.target, data: requestArg.data };
    }
    return undefined;
  }

  public static deviceId(snapshotArg: IDoorbirdSnapshot): string {
    return `${doorbirdDomain}.device.${this.uniqueBase(snapshotArg)}`;
  }

  public static slug(valueArg: string): string {
    return valueArg.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '') || doorbirdDomain;
  }

  public static normalizeMac(valueArg: string | undefined): string {
    const cleaned = (valueArg || '').replace(/[^a-fA-F0-9]/g, '').toLowerCase();
    return cleaned.length === 12 ? cleaned : '';
  }

  private static normalizeSnapshot(snapshotArg: IDoorbirdSnapshot, configArg: IDoorbirdConfig, sourceArg: TDoorbirdSnapshotSource): IDoorbirdSnapshot {
    const rawData = this.rawData(configArg, { info: snapshotArg.rawInfo, status: snapshotArg.status, favorites: snapshotArg.favorites, schedule: snapshotArg.schedule });
    const derivedDeviceInfo = this.deviceInfo(configArg, rawData.info, snapshotArg.online);
    const deviceInfo: IDoorbirdDeviceInfo = {
      ...derivedDeviceInfo,
      ...snapshotArg.deviceInfo,
      relays: snapshotArg.deviceInfo.relays?.length ? snapshotArg.deviceInfo.relays : derivedDeviceInfo.relays,
      online: snapshotArg.online,
    };
    return {
      ...snapshotArg,
      deviceInfo,
      cameras: snapshotArg.cameras?.length ? snapshotArg.cameras : this.cameras(configArg, deviceInfo, snapshotArg.online),
      buttons: snapshotArg.buttons?.length ? snapshotArg.buttons : this.buttons(configArg, deviceInfo, snapshotArg.online),
      events: snapshotArg.events?.length ? snapshotArg.events : this.events(configArg, deviceInfo, snapshotArg.online),
      status: this.status(snapshotArg.status),
      rawInfo: rawData.info,
      favorites: snapshotArg.favorites || rawData.favorites,
      schedule: snapshotArg.schedule || rawData.schedule,
      updatedAt: snapshotArg.updatedAt || new Date().toISOString(),
      source: snapshotArg.source || sourceArg,
    };
  }

  private static rawData(configArg: IDoorbirdConfig, rawDataArg?: Partial<IDoorbirdRawData>): Partial<IDoorbirdRawData> {
    return this.cleanAttributes({
      ...configArg.rawInfo ? { info: configArg.rawInfo } : {},
      ...configArg.status ? { status: configArg.status } : {},
      ...configArg.favorites ? { favorites: configArg.favorites } : {},
      ...configArg.schedule ? { schedule: configArg.schedule } : {},
      ...rawDataArg,
      info: rawDataArg?.info || configArg.rawInfo,
      status: rawDataArg?.status || configArg.status,
      favorites: rawDataArg?.favorites || configArg.favorites,
      schedule: rawDataArg?.schedule || configArg.schedule,
    });
  }

  private static deviceInfo(configArg: IDoorbirdConfig, infoArg: IDoorbirdInfo | undefined, onlineArg: boolean): IDoorbirdDeviceInfo {
    const endpoint = this.endpoint(configArg);
    const primaryMacAddress = this.normalizeMac(this.stringValue(infoArg?.PRIMARY_MAC_ADDR));
    const wifiMacAddress = this.normalizeMac(this.stringValue(infoArg?.WIFI_MAC_ADDR));
    const macAddress = this.normalizeMac(configArg.macAddress) || primaryMacAddress || wifiMacAddress;
    const firmware = this.stringValue(infoArg?.FIRMWARE);
    const buildNumber = this.stringValue(infoArg?.BUILD_NUMBER);
    const model = configArg.model || this.stringValue(infoArg?.['DEVICE-TYPE']) || this.stringValue(infoArg?.DEVICE_TYPE);
    const relays = this.relays(configArg, infoArg);
    const name = configArg.name || model || endpoint.host || 'DoorBird';
    return this.cleanAttributes({
      id: configArg.uniqueId || macAddress || (endpoint.host ? `${endpoint.host}:${endpoint.port || doorbirdDefaultPort}` : undefined) || name,
      name,
      manufacturer: configArg.manufacturer || doorbirdManufacturer,
      model,
      firmware,
      buildNumber,
      swVersion: firmware || buildNumber ? [firmware, buildNumber].filter(Boolean).join(' ') : undefined,
      macAddress: macAddress || undefined,
      primaryMacAddress: primaryMacAddress || undefined,
      wifiMacAddress: wifiMacAddress || undefined,
      host: endpoint.host,
      port: endpoint.port,
      protocol: endpoint.protocol,
      baseUrl: endpoint.baseUrl,
      rtspUrl: endpoint.host ? this.authenticatedUrl(configArg, '/mpeg/media.amp', configArg.rtspPort || doorbirdDefaultRtspPort, 'rtsp') : undefined,
      html5ViewerUrl: endpoint.host ? this.authenticatedUrl(configArg, '/bha-api/view.html') : undefined,
      relays,
      online: onlineArg,
    });
  }

  private static status(statusArg: IDoorbirdStatus | undefined): IDoorbirdStatus {
    return this.cleanAttributes({
      doorbell: statusArg?.doorbell,
      motion: statusArg?.motion,
      rawDoorbell: statusArg?.rawDoorbell,
      rawMotion: statusArg?.rawMotion,
      updatedAt: statusArg?.updatedAt || new Date().toISOString(),
    });
  }

  private static cameras(configArg: IDoorbirdConfig, deviceInfoArg: IDoorbirdDeviceInfo, onlineArg: boolean): IDoorbirdCameraSnapshot[] {
    const canFetchImage = Boolean(configArg.host || configArg.client?.getSnapshotImage || configArg.commandExecutor);
    return [
      {
        id: 'live',
        name: 'Live',
        kind: 'live',
        stillImageUrl: deviceInfoArg.host ? this.authenticatedUrl(configArg, '/bha-api/image.cgi') : undefined,
        liveVideoUrl: deviceInfoArg.host ? this.authenticatedUrl(configArg, '/bha-api/video.cgi') : undefined,
        rtspUrl: deviceInfoArg.host ? this.authenticatedUrl(configArg, '/mpeg/media.amp', configArg.rtspPort || doorbirdDefaultRtspPort, 'rtsp') : undefined,
        available: onlineArg && canFetchImage,
      },
      {
        id: 'last_ring',
        name: 'Last Ring',
        kind: 'last_ring',
        stillImageUrl: deviceInfoArg.host ? this.authenticatedUrl(configArg, '/bha-api/history.cgi?index=1&event=doorbell') : undefined,
        historyEvent: 'doorbell',
        historyIndex: 1,
        available: onlineArg && canFetchImage,
      },
      {
        id: 'last_motion',
        name: 'Last Motion',
        kind: 'last_motion',
        stillImageUrl: deviceInfoArg.host ? this.authenticatedUrl(configArg, '/bha-api/history.cgi?index=1&event=motionsensor') : undefined,
        historyEvent: 'motionsensor',
        historyIndex: 1,
        available: onlineArg && canFetchImage,
      },
    ];
  }

  private static buttons(configArg: IDoorbirdConfig, deviceInfoArg: IDoorbirdDeviceInfo, onlineArg: boolean): IDoorbirdButtonSnapshot[] {
    const relayAvailable = onlineArg && this.hasCommandTransport(configArg, 'energize_relay');
    const lightAvailable = onlineArg && this.hasCommandTransport(configArg, 'turn_light_on');
    const favoritesAvailable = onlineArg && this.hasCommandTransport(configArg, 'reset_favorites');
    const buttons: IDoorbirdButtonSnapshot[] = deviceInfoArg.relays.map((relayArg) => ({
      key: `relay_${this.slug(relayArg)}`,
      name: `Relay ${relayArg}`,
      action: 'energize_relay',
      relay: relayArg,
      available: relayAvailable,
    }));
    buttons.push({ key: 'ir_light', name: 'IR Light', action: 'turn_light_on', available: lightAvailable });
    buttons.push({ key: 'reset_favorites', name: 'Reset Favorites', action: 'reset_favorites', entityCategory: 'config', available: favoritesAvailable });
    return buttons;
  }

  private static events(configArg: IDoorbirdConfig, deviceInfoArg: IDoorbirdDeviceInfo, onlineArg: boolean): IDoorbirdEventSnapshot[] {
    const configuredEvents = configArg.events?.length ? configArg.events : ['doorbell', 'motion'];
    const base = this.slug(deviceInfoArg.name || doorbirdDomain);
    return configuredEvents.map((eventArg) => {
      const eventType = eventArg === 'motionsensor' ? 'motion' : eventArg;
      return {
        key: this.slug(eventArg),
        name: eventType === 'motion' ? 'Motion' : this.title(eventType),
        eventType,
        doorbirdEvent: `${base}_${this.slug(eventArg)}`,
        available: onlineArg,
      };
    });
  }

  private static entity(snapshotArg: IDoorbirdSnapshot, usedIdsArg: Map<string, number>, deviceIdArg: string, uniqueBaseArg: string, definitionArg: IDoorbirdEntityDefinition): IIntegrationEntity {
    const baseId = `${String(definitionArg.platform)}.${this.slug(definitionArg.name) || this.slug(definitionArg.key)}`;
    const seen = usedIdsArg.get(baseId) || 0;
    usedIdsArg.set(baseId, seen + 1);
    return {
      id: seen ? `${baseId}_${seen + 1}` : baseId,
      uniqueId: `${doorbirdDomain}_${uniqueBaseArg}_${this.slug(definitionArg.key)}`,
      integrationDomain: doorbirdDomain,
      deviceId: deviceIdArg,
      platform: definitionArg.platform,
      name: definitionArg.name,
      state: definitionArg.state,
      attributes: this.cleanAttributes({ key: definitionArg.key, ...definitionArg.attributes }),
      available: definitionArg.available,
    };
  }

  private static commandFromButton(buttonArg: IDoorbirdButtonSnapshot, requestArg: IServiceCallRequest): IDoorbirdCommandRequest {
    if (buttonArg.action === 'energize_relay') {
      return { action: 'energize_relay', relay: buttonArg.relay || '1', service: requestArg.service, target: requestArg.target, data: requestArg.data };
    }
    if (buttonArg.action === 'turn_light_on') {
      return { action: 'turn_light_on', service: requestArg.service, target: requestArg.target, data: requestArg.data };
    }
    return { action: 'reset_favorites', service: requestArg.service, target: requestArg.target, data: requestArg.data };
  }

  private static buttonFromRequest(snapshotArg: IDoorbirdSnapshot, requestArg: IServiceCallRequest): IDoorbirdButtonSnapshot | undefined {
    const target = requestArg.target.entityId || requestArg.target.deviceId || this.stringValue(requestArg.data?.entity_id ?? requestArg.data?.entityId ?? requestArg.data?.key ?? requestArg.data?.relay);
    if (!target) {
      return snapshotArg.buttons[0];
    }
    const buttonEntities = this.toEntities(snapshotArg).filter((entityArg) => entityArg.platform === 'button');
    const entity = buttonEntities.find((entityArg) => entityArg.id === target || entityArg.uniqueId === target || entityArg.attributes?.key === target || entityArg.attributes?.relay === target);
    const key = this.stringValue(entity?.attributes?.key) || target;
    return snapshotArg.buttons.find((buttonArg) => buttonArg.key === key || buttonArg.relay === target || buttonArg.name === target);
  }

  private static cameraIdFromRequest(snapshotArg: IDoorbirdSnapshot, requestArg: IServiceCallRequest): TDoorbirdCameraKind | undefined {
    const target = requestArg.target.entityId || this.stringValue(requestArg.data?.cameraId ?? requestArg.data?.camera_id ?? requestArg.data?.camera ?? requestArg.data?.kind);
    if (!target) {
      return 'live';
    }
    if (target === 'live' || target === 'last_ring' || target === 'last_motion') {
      return target;
    }
    const cameraEntities = this.toEntities(snapshotArg).filter((entityArg) => entityArg.platform === ('camera' as TEntityPlatform));
    const entity = cameraEntities.find((entityArg) => entityArg.id === target || entityArg.uniqueId === target || entityArg.attributes?.cameraId === target);
    const cameraId = this.stringValue(entity?.attributes?.cameraId);
    return cameraId === 'live' || cameraId === 'last_ring' || cameraId === 'last_motion' ? cameraId : 'live';
  }

  private static relayFromRequest(snapshotArg: IDoorbirdSnapshot, requestArg: IServiceCallRequest): string | undefined {
    const relay = this.stringValue(requestArg.data?.relay ?? requestArg.data?.r);
    if (relay) {
      return relay;
    }
    return this.buttonFromRequest(snapshotArg, requestArg)?.relay;
  }

  private static favoriteChangeFromData(dataArg: Record<string, unknown> | undefined): IDoorbirdFavoriteChange | undefined {
    const type = this.stringValue(dataArg?.type ?? dataArg?.favoriteType);
    const title = this.stringValue(dataArg?.title);
    const value = this.stringValue(dataArg?.value ?? dataArg?.url);
    if (!type || !title || !value) {
      return undefined;
    }
    return { type, title, value, id: this.stringValue(dataArg?.id ?? dataArg?.favoriteId) };
  }

  private static relays(configArg: IDoorbirdConfig, infoArg: IDoorbirdInfo | undefined): string[] {
    const rawRelays = configArg.relays || (Array.isArray(infoArg?.RELAYS) ? infoArg.RELAYS : []);
    return rawRelays.map((relayArg) => String(relayArg)).filter(Boolean);
  }

  private static hasCommandTransport(configArg: IDoorbirdConfig, actionArg: IDoorbirdCommandRequest['action']): boolean {
    if (configArg.commandExecutor || configArg.host) {
      return true;
    }
    if (actionArg === 'energize_relay') {
      return Boolean(configArg.client?.energizeRelay);
    }
    if (actionArg === 'turn_light_on') {
      return Boolean(configArg.client?.turnLightOn);
    }
    if (actionArg === 'reset_favorites') {
      return Boolean(configArg.client?.resetFavorites || configArg.client?.favorites && configArg.client?.deleteFavorite);
    }
    return Boolean(configArg.client);
  }

  private static deviceName(snapshotArg: IDoorbirdSnapshot): string {
    return snapshotArg.deviceInfo.name || snapshotArg.deviceInfo.host || 'DoorBird';
  }

  private static uniqueBase(snapshotArg: IDoorbirdSnapshot): string {
    return this.slug(snapshotArg.deviceInfo.macAddress || snapshotArg.deviceInfo.id || snapshotArg.deviceInfo.host || this.deviceName(snapshotArg));
  }

  private static hasRawData(rawDataArg: Partial<IDoorbirdRawData>): boolean {
    return Boolean(rawDataArg.info || rawDataArg.status || rawDataArg.favorites || rawDataArg.schedule);
  }

  private static endpoint(configArg: IDoorbirdConfig): { protocol?: TDoorbirdProtocol; host?: string; port?: number; baseUrl?: string } {
    const parsed = this.parseEndpoint(configArg.host);
    if (parsed) {
      return parsed;
    }
    const protocol: TDoorbirdProtocol = configArg.protocol || (configArg.ssl || configArg.tls ? 'https' : 'http');
    const port = configArg.port || (protocol === 'https' ? doorbirdDefaultHttpsPort : doorbirdDefaultPort);
    return {
      protocol,
      host: configArg.host,
      port: configArg.host ? port : configArg.port,
      baseUrl: configArg.host ? `${protocol}://${this.hostForUrl(configArg.host)}${port && port !== (protocol === 'https' ? 443 : 80) ? `:${port}` : ''}` : undefined,
    };
  }

  private static parseEndpoint(valueArg: string | undefined): { protocol: TDoorbirdProtocol; host: string; port: number; baseUrl: string } | undefined {
    if (!valueArg || !/^[a-z][a-z0-9+.-]*:\/\//i.test(valueArg)) {
      return undefined;
    }
    try {
      const url = new URL(valueArg);
      const protocol: TDoorbirdProtocol = url.protocol === 'https:' ? 'https' : 'http';
      const port = url.port ? Number(url.port) : protocol === 'https' ? doorbirdDefaultHttpsPort : doorbirdDefaultPort;
      return { protocol, host: url.hostname, port, baseUrl: `${protocol}://${url.hostname}${port !== (protocol === 'https' ? 443 : 80) ? `:${port}` : ''}` };
    } catch {
      return undefined;
    }
  }

  private static authenticatedUrl(configArg: IDoorbirdConfig, pathArg: string, portArg?: number, protocolArg?: string): string | undefined {
    const endpoint = this.endpoint(configArg);
    if (!endpoint.host) {
      return undefined;
    }
    const protocol = protocolArg || endpoint.protocol || 'http';
    const defaultPort = protocol === 'rtsp' ? doorbirdDefaultRtspPort : protocol === 'https' ? doorbirdDefaultHttpsPort : doorbirdDefaultPort;
    const port = portArg || endpoint.port || defaultPort;
    const credentials = configArg.username || configArg.password !== undefined
      ? `${encodeURIComponent(configArg.username || '')}:${encodeURIComponent(configArg.password || '')}@`
      : '';
    return `${protocol}://${credentials}${this.hostForUrl(endpoint.host)}${port !== defaultPort ? `:${port}` : ''}${pathArg.startsWith('/') ? pathArg : `/${pathArg}`}`;
  }

  private static hostForUrl(hostArg: string): string {
    return hostArg.includes(':') && !hostArg.startsWith('[') ? `[${hostArg}]` : hostArg;
  }

  private static stringValue(valueArg: unknown): string | undefined {
    return typeof valueArg === 'string' && valueArg.trim() ? valueArg.trim() : typeof valueArg === 'number' ? String(valueArg) : undefined;
  }

  private static title(valueArg: string): string {
    return `${valueArg.charAt(0).toUpperCase()}${valueArg.slice(1).replace(/_/g, ' ')}`;
  }

  private static cleanAttributes<TRecord extends Record<string, unknown>>(attributesArg: TRecord): TRecord {
    return Object.fromEntries(Object.entries(attributesArg).filter(([, valueArg]) => valueArg !== undefined)) as TRecord;
  }

  private static clone<TValue>(valueArg: TValue): TValue {
    return JSON.parse(JSON.stringify(valueArg)) as TValue;
  }
}
