import type * as shxInterfaces from '@smarthome.exchange/interfaces';
import { BaseIntegration } from '../../core/classes.baseintegration.js';
import type { IIntegrationEntity, IIntegrationRuntime, IIntegrationSetupContext, IServiceCallRequest, IServiceCallResult } from '../../core/types.js';
import { DenonavrClient } from './denonavr.classes.client.js';
import { DenonavrConfigFlow } from './denonavr.classes.configflow.js';
import { createDenonavrDiscoveryDescriptor } from './denonavr.discovery.js';
import { DenonavrMapper } from './denonavr.mapper.js';
import type { IDenonavrConfig, TDenonavrCommand, TDenonavrZone } from './denonavr.types.js';

export class DenonavrIntegration extends BaseIntegration<IDenonavrConfig> {
  public readonly domain = 'denonavr';
  public readonly displayName = 'Denon AVR Network Receivers';
  public readonly status = 'control-runtime' as const;
  public readonly discoveryDescriptor = createDenonavrDiscoveryDescriptor();
  public readonly configFlow = new DenonavrConfigFlow();
  public readonly metadata = {
    source: 'home-assistant/core',
    upstreamPath: 'homeassistant/components/denonavr',
    upstreamDomain: 'denonavr',
    integrationType: 'device',
    iotClass: 'local_push',
    requirements: ['denonavr==1.3.2'],
    dependencies: [],
    afterDependencies: [],
    codeowners: ['@ol-iver', '@starkillerOG'],
    configFlow: true,
    documentation: 'https://www.home-assistant.io/integrations/denonavr',
  };

  public async setup(configArg: IDenonavrConfig, contextArg: IIntegrationSetupContext): Promise<IIntegrationRuntime> {
    void contextArg;
    return new DenonavrRuntime(new DenonavrClient(configArg));
  }

  public async destroy(): Promise<void> {}
}

export class HomeAssistantDenonavrIntegration extends DenonavrIntegration {}

class DenonavrRuntime implements IIntegrationRuntime {
  public domain = 'denonavr';

  constructor(private readonly client: DenonavrClient) {}

  public async devices(): Promise<shxInterfaces.data.IDeviceDefinition[]> {
    return DenonavrMapper.toDevices(await this.client.getSnapshot());
  }

  public async entities(): Promise<IIntegrationEntity[]> {
    return DenonavrMapper.toEntities(await this.client.getSnapshot());
  }

  public async callService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
    if (requestArg.domain !== 'media_player') {
      return { success: false, error: `Unsupported Denon AVR service domain: ${requestArg.domain}` };
    }

    const zone = this.zoneFromRequest(requestArg);
    const command = this.commandFromService(requestArg);
    if (!command) {
      return { success: false, error: `Unsupported Denon AVR media_player service: ${requestArg.service}` };
    }

    try {
      const result = await this.client.execute({
        command,
        zone,
        source: this.stringData(requestArg, 'source'),
        volumeLevel: this.numberData(requestArg, 'volume_level'),
        muted: this.boolData(requestArg, 'is_volume_muted') ?? this.boolData(requestArg, 'mute'),
      });
      return { success: true, data: result };
    } catch (error) {
      return { success: false, error: error instanceof Error ? error.message : String(error) };
    }
  }

  public async destroy(): Promise<void> {
    await this.client.destroy();
  }

  private commandFromService(requestArg: IServiceCallRequest): TDenonavrCommand | undefined {
    if (requestArg.service === 'turn_on') {
      return 'turn_on';
    }
    if (requestArg.service === 'turn_off') {
      return 'turn_off';
    }
    if (requestArg.service === 'volume_up') {
      return 'volume_up';
    }
    if (requestArg.service === 'volume_down') {
      return 'volume_down';
    }
    if (requestArg.service === 'volume_set') {
      return 'set_volume';
    }
    if (requestArg.service === 'volume_mute') {
      return 'mute';
    }
    if (requestArg.service === 'select_source') {
      return 'select_source';
    }
    if (requestArg.service === 'media_play' || requestArg.service === 'play') {
      return 'play';
    }
    if (requestArg.service === 'media_pause' || requestArg.service === 'pause') {
      return 'pause';
    }
    if (requestArg.service === 'media_stop' || requestArg.service === 'stop') {
      return 'stop';
    }
    if (requestArg.service === 'media_play_pause' || requestArg.service === 'play_pause') {
      return 'play_pause';
    }
    if (requestArg.service === 'media_previous_track' || requestArg.service === 'previous_track') {
      return 'previous_track';
    }
    if (requestArg.service === 'media_next_track' || requestArg.service === 'next_track') {
      return 'next_track';
    }
    return undefined;
  }

  private zoneFromRequest(requestArg: IServiceCallRequest): TDenonavrZone {
    const zone = this.stringData(requestArg, 'zone');
    if (zone === 'Zone2' || zone === 'zone2') {
      return 'Zone2';
    }
    if (zone === 'Zone3' || zone === 'zone3') {
      return 'Zone3';
    }
    const entityId = requestArg.target.entityId?.toLowerCase() || '';
    if (entityId.includes('zone2')) {
      return 'Zone2';
    }
    if (entityId.includes('zone3')) {
      return 'Zone3';
    }
    return 'Main';
  }

  private stringData(requestArg: IServiceCallRequest, keyArg: string): string | undefined {
    const value = requestArg.data?.[keyArg];
    return typeof value === 'string' ? value : undefined;
  }

  private numberData(requestArg: IServiceCallRequest, keyArg: string): number | undefined {
    const value = requestArg.data?.[keyArg];
    return typeof value === 'number' ? value : undefined;
  }

  private boolData(requestArg: IServiceCallRequest, keyArg: string): boolean | undefined {
    const value = requestArg.data?.[keyArg];
    return typeof value === 'boolean' ? value : undefined;
  }
}
