import * as plugins from '../../plugins.js';
import type { IIntegrationEntity, IIntegrationEvent } from '../../core/types.js';
import type { IYeelightBulbInfo, IYeelightBulbProperties, IYeelightEvent, IYeelightSnapshot } from './yeelight.types.js';

const sensorProperties: Array<{ key: keyof IYeelightBulbProperties; name: string; unit?: string; binary?: boolean }> = [
  { key: 'ct', name: 'Color temperature', unit: 'K' },
  { key: 'rgb', name: 'RGB' },
  { key: 'hue', name: 'Hue' },
  { key: 'sat', name: 'Saturation', unit: '%' },
  { key: 'color_mode', name: 'Color mode' },
  { key: 'flowing', name: 'Color flow', binary: true },
  { key: 'active_mode', name: 'Active mode' },
  { key: 'nl_br', name: 'Nightlight brightness', unit: '%' },
  { key: 'bg_power', name: 'Ambient power', binary: true },
  { key: 'bg_bright', name: 'Ambient brightness', unit: '%' },
  { key: 'bg_ct', name: 'Ambient color temperature', unit: 'K' },
  { key: 'bg_rgb', name: 'Ambient RGB' },
];

export class YeelightMapper {
  public static toDevices(snapshotArg: IYeelightSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
    const updatedAt = new Date().toISOString();
    return snapshotArg.bulbs.map((bulbArg) => {
      const state = this.bulbState(bulbArg);
      const properties = bulbArg.properties || {};
      const features: plugins.shxInterfaces.data.IDeviceFeature[] = [
        { id: 'power', capability: 'light', name: 'Power', readable: true, writable: true },
      ];
      const deviceState: plugins.shxInterfaces.data.IDeviceState[] = [
        { featureId: 'power', value: state.on, updatedAt },
      ];
      if (state.brightness !== undefined || this.supports(bulbArg, 'set_bright')) {
        features.push({ id: 'brightness', capability: 'light', name: 'Brightness', readable: true, writable: true, unit: '%' });
        deviceState.push({ featureId: 'brightness', value: state.brightness ?? null, updatedAt });
      }
      if (state.colorTempKelvin !== undefined || this.supports(bulbArg, 'set_ct_abx')) {
        features.push({ id: 'color_temperature', capability: 'light', name: 'Color temperature', readable: true, writable: true, unit: 'K' });
        deviceState.push({ featureId: 'color_temperature', value: state.colorTempKelvin ?? null, updatedAt });
      }
      if (state.rgbColor !== undefined || this.supports(bulbArg, 'set_rgb')) {
        features.push({ id: 'rgb', capability: 'light', name: 'RGB color', readable: true, writable: true });
        deviceState.push({ featureId: 'rgb', value: state.rgbColor ? state.rgbColor.join(',') : null, updatedAt });
      }
      for (const sensor of sensorProperties) {
        const value = properties[sensor.key];
        if (value === undefined || value === null) {
          continue;
        }
        const featureId = String(sensor.key);
        if (features.some((featureArg) => featureArg.id === featureId)) {
          continue;
        }
        features.push({ id: featureId, capability: 'sensor', name: sensor.name, readable: true, writable: false, unit: sensor.unit });
        deviceState.push({ featureId, value: this.deviceStateValue(sensor.binary ? this.binaryState(value) : this.propertyValue(value)), updatedAt });
      }
      return {
        id: this.deviceId(bulbArg),
        integrationDomain: 'yeelight',
        name: this.bulbName(bulbArg),
        protocol: 'unknown',
        manufacturer: 'Yeelight',
        model: bulbArg.model || bulbArg.capabilities?.model,
        online: bulbArg.available !== false && (snapshotArg.connected || Boolean(bulbArg.properties)),
        features,
        state: deviceState,
        metadata: {
          host: bulbArg.host,
          port: bulbArg.port || 55443,
          firmwareVersion: bulbArg.fwVersion || bulbArg.capabilities?.fw_ver,
          support: bulbArg.support || bulbArg.capabilities?.support?.split(' ').filter(Boolean),
        },
      };
    });
  }

  public static toEntities(snapshotArg: IYeelightSnapshot): IIntegrationEntity[] {
    const entities: IIntegrationEntity[] = [];
    for (const bulb of snapshotArg.bulbs) {
      const deviceId = this.deviceId(bulb);
      const name = this.bulbName(bulb);
      const slug = this.slug(name);
      const state = this.bulbState(bulb);
      entities.push({
        id: `light.${slug}`,
        uniqueId: `yeelight_${this.slug(bulb.id || bulb.host || name)}_light`,
        integrationDomain: 'yeelight',
        deviceId,
        platform: 'light',
        name,
        state: state.on ? 'on' : 'off',
        attributes: {
          brightness: state.brightness,
          colorTempKelvin: state.colorTempKelvin,
          rgbColor: state.rgbColor,
          hsColor: state.hsColor,
          colorMode: state.colorMode,
          flowing: state.flowing,
          nightLight: state.nightLight,
          host: bulb.host,
          model: bulb.model || bulb.capabilities?.model,
        },
        available: bulb.available !== false,
      });
      for (const sensor of sensorProperties) {
        const value = bulb.properties?.[sensor.key];
        if (value === undefined || value === null) {
          continue;
        }
        const platform = sensor.binary ? 'binary_sensor' : 'sensor';
        const sensorSlug = this.slug(`${name} ${sensor.name}`);
        entities.push({
          id: `${platform}.${sensorSlug}`,
          uniqueId: `yeelight_${this.slug(bulb.id || bulb.host || name)}_${String(sensor.key)}`,
          integrationDomain: 'yeelight',
          deviceId,
          platform,
          name: `${name} ${sensor.name}`,
          state: sensor.binary ? this.binaryState(value) ? 'on' : 'off' : this.propertyValue(value),
          attributes: sensor.unit ? { unit: sensor.unit } : undefined,
          available: bulb.available !== false,
        });
      }
    }
    return entities;
  }

  public static toIntegrationEvent(eventArg: IYeelightEvent): IIntegrationEvent {
    return {
      type: eventArg.type === 'error' ? 'error' : 'state_changed',
      integrationDomain: 'yeelight',
      deviceId: eventArg.bulbId,
      entityId: eventArg.entityId,
      data: eventArg,
      timestamp: eventArg.timestamp || Date.now(),
    };
  }

  private static bulbState(bulbArg: IYeelightBulbInfo) {
    if (bulbArg.state) {
      return bulbArg.state;
    }
    const properties = bulbArg.properties || {};
    const power = properties.main_power ?? properties.power;
    const brightness = this.numberValue(properties.bright);
    return {
      on: power === 'on',
      brightness,
      colorTempKelvin: this.numberValue(properties.ct),
      rgbColor: this.rgbValue(properties.rgb),
      hsColor: this.hsValue(properties.hue, properties.sat),
      colorMode: properties.color_mode === undefined || properties.color_mode === null ? undefined : String(properties.color_mode),
      flowing: this.binaryState(properties.flowing),
      nightLight: properties.active_mode !== undefined ? String(properties.active_mode) === '1' : this.numberValue(properties.nl_br) ? this.numberValue(properties.nl_br)! > 0 : undefined,
    };
  }

  private static supports(bulbArg: IYeelightBulbInfo, commandArg: string): boolean {
    const support = bulbArg.support || bulbArg.capabilities?.support?.split(' ').filter(Boolean) || [];
    return support.includes(commandArg);
  }

  private static deviceId(bulbArg: IYeelightBulbInfo): string {
    return `yeelight.bulb.${this.slug(bulbArg.id || bulbArg.host || this.bulbName(bulbArg))}`;
  }

  private static bulbName(bulbArg: IYeelightBulbInfo): string {
    return bulbArg.name || bulbArg.properties?.name || bulbArg.capabilities?.name || bulbArg.model || bulbArg.host || 'Yeelight Bulb';
  }

  private static rgbValue(valueArg: unknown): [number, number, number] | undefined {
    const numeric = this.numberValue(valueArg);
    if (numeric === undefined) {
      return undefined;
    }
    return [(numeric >> 16) & 0xff, (numeric >> 8) & 0xff, numeric & 0xff];
  }

  private static hsValue(hueArg: unknown, satArg: unknown): [number, number] | undefined {
    const hue = this.numberValue(hueArg);
    const sat = this.numberValue(satArg);
    return hue === undefined || sat === undefined ? undefined : [hue, sat];
  }

  private static numberValue(valueArg: unknown): number | undefined {
    if (typeof valueArg === 'number' && Number.isFinite(valueArg)) {
      return valueArg;
    }
    if (typeof valueArg === 'string' && valueArg.trim() && Number.isFinite(Number(valueArg))) {
      return Number(valueArg);
    }
    return undefined;
  }

  private static binaryState(valueArg: unknown): boolean {
    return valueArg === true || valueArg === 'on' || valueArg === '1' || valueArg === 1;
  }

  private static propertyValue(valueArg: unknown): string | number | boolean | null {
    const numeric = this.numberValue(valueArg);
    if (numeric !== undefined) {
      return numeric;
    }
    if (typeof valueArg === 'string' || typeof valueArg === 'boolean' || valueArg === null) {
      return valueArg;
    }
    return valueArg === undefined ? null : String(valueArg);
  }

  private static deviceStateValue(valueArg: unknown): plugins.shxInterfaces.data.TDeviceStateValue {
    if (typeof valueArg === 'string' || typeof valueArg === 'number' || typeof valueArg === 'boolean' || valueArg === null) {
      return valueArg;
    }
    return String(valueArg);
  }

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