import * as plugins from '../../plugins.js';
import type { IIntegrationEntity } from '../../core/types.js';
import { androidtvRemoteKnownApps } from './androidtv_remote.constants.js';
import type { IAndroidtvRemoteApp, IAndroidtvRemoteSnapshot, IAndroidtvRemoteVolumeInfo } from './androidtv_remote.types.js';

export class AndroidtvRemoteMapper {
  public static toDevices(snapshotArg: IAndroidtvRemoteSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
    const updatedAt = snapshotArg.updatedAt || new Date().toISOString();
    return [{
      id: this.deviceId(snapshotArg),
      integrationDomain: 'androidtv_remote',
      name: this.deviceName(snapshotArg),
      protocol: 'unknown',
      manufacturer: snapshotArg.deviceInfo.manufacturer || 'Android',
      model: snapshotArg.deviceInfo.model || 'Android TV Remote',
      online: this.available(snapshotArg),
      features: [
        { id: 'power', capability: 'media', name: 'Power', readable: true, writable: true },
        { id: 'media_state', capability: 'media', name: 'Media state', readable: true, writable: false },
        { id: 'activity', capability: 'media', name: 'Activity', readable: true, writable: true },
        { id: 'volume', capability: 'media', name: 'Volume', readable: true, writable: true },
        { id: 'mute', capability: 'media', name: 'Mute', readable: true, writable: true },
        { id: 'remote_key', capability: 'media', name: 'Remote key', readable: false, writable: true },
      ],
      state: [
        { featureId: 'power', value: this.powerState(snapshotArg), updatedAt },
        { featureId: 'media_state', value: this.mediaState(snapshotArg), updatedAt },
        { featureId: 'activity', value: this.activity(snapshotArg) || null, updatedAt },
        { featureId: 'volume', value: this.volumePercent(snapshotArg), updatedAt },
        { featureId: 'mute', value: this.muted(snapshotArg), updatedAt },
      ],
      metadata: {
        host: snapshotArg.deviceInfo.host,
        protocol: 'androidtvremote2',
        apiPort: snapshotArg.deviceInfo.apiPort,
        pairPort: snapshotArg.deviceInfo.pairPort,
        macAddress: snapshotArg.deviceInfo.macAddress,
        softwareVersion: snapshotArg.deviceInfo.softwareVersion,
        appVersion: snapshotArg.deviceInfo.appVersion,
        currentApp: snapshotArg.state.currentApp,
        voiceEnabled: snapshotArg.state.voiceEnabled,
        apps: snapshotArg.apps.map((appArg) => ({ id: appArg.id, name: this.appName(appArg), icon: appArg.icon, link: appArg.link })),
      },
    }];
  }

  public static toEntities(snapshotArg: IAndroidtvRemoteSnapshot): IIntegrationEntity[] {
    return [{
      id: `media_player.${this.slug(this.deviceName(snapshotArg))}`,
      uniqueId: `androidtv_remote_${this.slug(this.stableDeviceKey(snapshotArg))}`,
      integrationDomain: 'androidtv_remote',
      deviceId: this.deviceId(snapshotArg),
      platform: 'media_player',
      name: this.deviceName(snapshotArg),
      state: this.mediaState(snapshotArg),
      attributes: {
        appId: snapshotArg.state.currentApp,
        appName: snapshotArg.state.currentAppName || (snapshotArg.state.currentApp ? this.appNameById(snapshotArg, snapshotArg.state.currentApp) : undefined),
        currentActivity: this.activity(snapshotArg),
        activityList: this.activityList(snapshotArg),
        source: this.activity(snapshotArg),
        sourceList: this.activityList(snapshotArg),
        volumeLevel: this.normalizedVolumeLevel(snapshotArg),
        isVolumeMuted: this.muted(snapshotArg),
        assumedState: true,
        voiceEnabled: snapshotArg.state.voiceEnabled,
        rawState: snapshotArg.state.rawState,
      },
      available: this.available(snapshotArg),
    }];
  }

  public static mediaState(snapshotArg: IAndroidtvRemoteSnapshot): string {
    if (!this.available(snapshotArg)) {
      return 'unavailable';
    }
    const rawState = String(snapshotArg.state.mediaState || snapshotArg.state.rawState || '').toLowerCase();
    if (snapshotArg.state.isOn === false || snapshotArg.state.powerState === 'off' || rawState === 'off') {
      return 'off';
    }
    if (['playing', 'paused', 'stopped', 'idle', 'buffering', 'on'].includes(rawState)) {
      return rawState;
    }
    if (snapshotArg.state.isOn === true || snapshotArg.state.currentApp) {
      return 'on';
    }
    return 'unknown';
  }

  public static powerState(snapshotArg: IAndroidtvRemoteSnapshot): string {
    if (snapshotArg.state.isOn === true || snapshotArg.state.powerState === 'on') {
      return 'on';
    }
    if (snapshotArg.state.isOn === false || snapshotArg.state.powerState === 'off' || String(snapshotArg.state.mediaState || '').toLowerCase() === 'off') {
      return 'off';
    }
    return this.available(snapshotArg) && snapshotArg.state.currentApp ? 'on' : 'unknown';
  }

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

  private static activity(snapshotArg: IAndroidtvRemoteSnapshot): string | undefined {
    return snapshotArg.state.currentActivity || snapshotArg.state.currentAppName || (snapshotArg.state.currentApp ? this.appNameById(snapshotArg, snapshotArg.state.currentApp) || snapshotArg.state.currentApp : undefined);
  }

  private static activityList(snapshotArg: IAndroidtvRemoteSnapshot): string[] {
    const activities = new Set<string>();
    for (const appArg of snapshotArg.apps) {
      const name = this.appName(appArg);
      if (name) {
        activities.add(name);
      }
    }
    return [...activities];
  }

  private static appNameById(snapshotArg: IAndroidtvRemoteSnapshot, appIdArg: string): string | undefined {
    return snapshotArg.apps.find((appArg) => appArg.id === appIdArg)?.name || androidtvRemoteKnownApps[appIdArg];
  }

  private static appName(appArg: IAndroidtvRemoteApp): string {
    return appArg.name || androidtvRemoteKnownApps[appArg.id] || appArg.id;
  }

  private static normalizedVolumeLevel(snapshotArg: IAndroidtvRemoteSnapshot): number | undefined {
    if (typeof snapshotArg.state.volumeLevel === 'number') {
      return Math.max(0, Math.min(1, snapshotArg.state.volumeLevel));
    }
    return this.volumeLevelFromInfo(snapshotArg.state.volumeInfo);
  }

  private static volumePercent(snapshotArg: IAndroidtvRemoteSnapshot): number | null {
    const level = this.normalizedVolumeLevel(snapshotArg);
    return typeof level === 'number' ? Math.round(level * 100) : null;
  }

  private static volumeLevelFromInfo(volumeInfoArg?: IAndroidtvRemoteVolumeInfo): number | undefined {
    if (!volumeInfoArg || typeof volumeInfoArg.level !== 'number' || typeof volumeInfoArg.max !== 'number' || volumeInfoArg.max <= 0) {
      return undefined;
    }
    return Math.max(0, Math.min(1, volumeInfoArg.level / volumeInfoArg.max));
  }

  private static muted(snapshotArg: IAndroidtvRemoteSnapshot): boolean | null {
    return snapshotArg.state.isVolumeMuted ?? snapshotArg.state.volumeInfo?.muted ?? null;
  }

  private static deviceId(snapshotArg: IAndroidtvRemoteSnapshot): string {
    return `androidtv_remote.device.${this.slug(this.stableDeviceKey(snapshotArg))}`;
  }

  private static stableDeviceKey(snapshotArg: IAndroidtvRemoteSnapshot): string {
    return snapshotArg.deviceInfo.id || snapshotArg.deviceInfo.macAddress || snapshotArg.deviceInfo.host || this.deviceName(snapshotArg);
  }

  private static deviceName(snapshotArg: IAndroidtvRemoteSnapshot): string {
    return snapshotArg.deviceInfo.name || snapshotArg.deviceInfo.model || snapshotArg.deviceInfo.host || 'Android TV Remote';
  }

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