import * as plugins from '../../plugins.js';
import type { IIntegrationEntity } from '../../core/types.js';
import { harmonyDomain, harmonyPowerOffActivity, harmonySelectPowerOffOption } from './harmony.constants.js';
import type { IHarmonyActivity, IHarmonyDevice, IHarmonySnapshot } from './harmony.types.js';

export class HarmonyMapper {
  public static toDevices(snapshotArg: IHarmonySnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
    const updatedAt = snapshotArg.updatedAt || new Date().toISOString();
    return [{
      id: this.deviceId(snapshotArg),
      integrationDomain: harmonyDomain,
      name: this.deviceName(snapshotArg),
      protocol: 'unknown',
      manufacturer: snapshotArg.deviceInfo.manufacturer || 'Logitech',
      model: snapshotArg.deviceInfo.model || 'Harmony Hub',
      online: this.available(snapshotArg),
      features: [
        { id: 'connectivity', capability: 'sensor', name: 'Connectivity', readable: true, writable: false },
        { id: 'power', capability: 'media', name: 'Power', readable: true, writable: true },
        { id: 'activity', capability: 'media', name: 'Activity', readable: true, writable: true },
        { id: 'activity_starting', capability: 'sensor', name: 'Activity starting', readable: true, writable: false },
        { id: 'remote_command', capability: 'media', name: 'Remote command', readable: false, writable: true },
        { id: 'channel', capability: 'media', name: 'Channel', readable: false, writable: true },
      ],
      state: [
        { featureId: 'connectivity', value: this.available(snapshotArg) ? 'online' : 'offline', updatedAt },
        { featureId: 'power', value: this.powerState(snapshotArg), updatedAt },
        { featureId: 'activity', value: this.currentActivity(snapshotArg), updatedAt },
        { featureId: 'activity_starting', value: snapshotArg.state.activityStarting || null, updatedAt },
      ],
      metadata: this.cleanAttributes({
        host: snapshotArg.deviceInfo.host,
        port: snapshotArg.deviceInfo.port,
        remoteId: snapshotArg.deviceInfo.remoteId || snapshotArg.deviceInfo.hubId || snapshotArg.deviceInfo.id,
        softwareVersion: snapshotArg.deviceInfo.softwareVersion || snapshotArg.deviceInfo.firmwareVersion,
        currentActivityId: snapshotArg.state.currentActivityId,
        currentActivity: this.currentActivity(snapshotArg),
        lastActivity: snapshotArg.state.lastActivity,
        activities: this.activityList(snapshotArg),
        devices: snapshotArg.devices.map((deviceArg) => this.deviceMetadata(deviceArg)),
      }),
    }];
  }

  public static toEntities(snapshotArg: IHarmonySnapshot): IIntegrationEntity[] {
    const base = this.slug(this.deviceName(snapshotArg));
    const deviceId = this.deviceId(snapshotArg);
    const currentActivity = this.currentActivity(snapshotArg);
    const activityList = this.activityList(snapshotArg);
    return [
      {
        id: `media_player.${base}`,
        uniqueId: `harmony_${this.slug(this.stableDeviceKey(snapshotArg))}_remote`,
        integrationDomain: harmonyDomain,
        deviceId,
        platform: 'media_player',
        name: this.deviceName(snapshotArg),
        state: this.mediaState(snapshotArg),
        attributes: this.cleanAttributes({
          currentActivity,
          activityList,
          source: currentActivity === harmonyPowerOffActivity ? undefined : currentActivity,
          sourceList: activityList,
          activityStarting: snapshotArg.state.activityStarting,
          lastActivity: snapshotArg.state.lastActivity,
          devicesList: snapshotArg.devices.map((deviceArg) => deviceArg.label),
          supportedFeatures: ['activity', 'remote_send_command', 'turn_on', 'turn_off', 'change_channel'],
          assumedState: true,
        }),
        available: this.available(snapshotArg),
      },
      {
        id: `select.${base}_activities`,
        uniqueId: `harmony_${this.slug(this.stableDeviceKey(snapshotArg))}_activities`,
        integrationDomain: harmonyDomain,
        deviceId,
        platform: 'select',
        name: `${this.deviceName(snapshotArg)} Activities`,
        state: currentActivity === harmonyPowerOffActivity ? harmonySelectPowerOffOption : currentActivity,
        attributes: {
          options: [harmonySelectPowerOffOption, ...activityList],
        },
        available: this.available(snapshotArg),
      },
    ];
  }

  public static deviceId(snapshotArg: IHarmonySnapshot): string {
    return `harmony.device.${this.slug(this.stableDeviceKey(snapshotArg))}`;
  }

  public static mediaState(snapshotArg: IHarmonySnapshot): string {
    if (!this.available(snapshotArg)) {
      return 'unavailable';
    }
    return this.currentActivity(snapshotArg) === harmonyPowerOffActivity ? 'off' : 'on';
  }

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

  private static available(snapshotArg: IHarmonySnapshot): boolean {
    return snapshotArg.state.available !== false;
  }

  private static powerState(snapshotArg: IHarmonySnapshot): string {
    if (!this.available(snapshotArg)) {
      return 'unavailable';
    }
    return this.currentActivity(snapshotArg) === harmonyPowerOffActivity ? 'off' : 'on';
  }

  private static currentActivity(snapshotArg: IHarmonySnapshot): string {
    return snapshotArg.state.currentActivity || this.activityLabelForId(snapshotArg.activities, snapshotArg.state.currentActivityId) || harmonyPowerOffActivity;
  }

  private static activityList(snapshotArg: IHarmonySnapshot): string[] {
    return snapshotArg.activities
      .filter((activityArg) => !this.isPowerOffActivity(activityArg))
      .map((activityArg) => activityArg.label)
      .sort((leftArg, rightArg) => leftArg.localeCompare(rightArg));
  }

  private static isPowerOffActivity(activityArg: IHarmonyActivity): boolean {
    return activityArg.isPowerOff === true || activityArg.id === '-1' || activityArg.label === harmonyPowerOffActivity;
  }

  private static activityLabelForId(activitiesArg: IHarmonyActivity[], idArg?: string): string | undefined {
    return idArg ? activitiesArg.find((activityArg) => activityArg.id === idArg)?.label : undefined;
  }

  private static stableDeviceKey(snapshotArg: IHarmonySnapshot): string {
    return snapshotArg.deviceInfo.id || snapshotArg.deviceInfo.remoteId || snapshotArg.deviceInfo.hubId || snapshotArg.deviceInfo.host || this.deviceName(snapshotArg);
  }

  private static deviceName(snapshotArg: IHarmonySnapshot): string {
    return snapshotArg.deviceInfo.name || snapshotArg.deviceInfo.host || 'Harmony Hub';
  }

  private static deviceMetadata(deviceArg: IHarmonyDevice): Record<string, unknown> {
    return this.cleanAttributes({
      id: deviceArg.id,
      label: deviceArg.label,
      manufacturer: deviceArg.manufacturer,
      model: deviceArg.model,
      commands: deviceArg.commands?.map((commandArg) => commandArg.name),
      commandGroups: deviceArg.commandGroups?.map((groupArg) => ({
        name: groupArg.name,
        commands: groupArg.commands.map((commandArg) => commandArg.name),
      })),
    });
  }

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