import type * as shxInterfaces from '@smarthome.exchange/interfaces';
import { BaseIntegration } from '../../core/classes.baseintegration.js';
import type { IIntegrationEntity, IIntegrationEvent, IIntegrationRuntime, IIntegrationSetupContext, IServiceCallRequest, IServiceCallResult } from '../../core/types.js';
import { SynologyDsmClient } from './synology_dsm.classes.client.js';
import { SynologyDsmConfigFlow } from './synology_dsm.classes.configflow.js';
import { createSynologyDsmDiscoveryDescriptor } from './synology_dsm.discovery.js';
import { SynologyDsmMapper } from './synology_dsm.mapper.js';
import type { ISynologyDsmConfig } from './synology_dsm.types.js';
import { synologyDsmDomain } from './synology_dsm.types.js';

export class SynologyDsmIntegration extends BaseIntegration<ISynologyDsmConfig> {
  public readonly domain = synologyDsmDomain;
  public readonly displayName = 'Synology DSM';
  public readonly status = 'control-runtime' as const;
  public readonly discoveryDescriptor = createSynologyDsmDiscoveryDescriptor();
  public readonly configFlow = new SynologyDsmConfigFlow();
  public readonly metadata = {
    source: 'home-assistant/core',
    upstreamPath: 'homeassistant/components/synology_dsm',
    upstreamDomain: synologyDsmDomain,
    integrationType: 'device',
    iotClass: 'local_polling',
    requirements: ['py-synologydsm-api==2.7.3'],
    dependencies: ['http'],
    afterDependencies: [] as string[],
    codeowners: ['@Quentame', '@mib1185'],
    documentation: 'https://www.home-assistant.io/integrations/synology_dsm',
    configFlow: true,
    runtime: {
      mode: 'native TypeScript snapshot/provider Synology DSM mapping',
      platforms: ['binary_sensor', 'button', 'camera-metadata', 'sensor', 'switch', 'update'],
      services: ['snapshot', 'status', 'refresh', 'reboot', 'shutdown', 'set_home_mode', 'camera.enable_motion_detection', 'camera.disable_motion_detection'],
    },
    discovery: {
      manual: true,
      ssdp: 'Synology Basic:1 SSDP advertisements from the Home Assistant manifest are recognized.',
      zeroconf: 'Synology _http._tcp.local zeroconf advertisements with vendor metadata are recognized.',
      http: 'Manual/local DSM HTTP endpoint candidates are recognized; no active LAN scan is performed.',
    },
    localApi: {
      implemented: [
        'manual/local NAS candidates and config flow',
        'snapshot/native-client mapping for DSM system, utilization, network, storage, volume, disk, security, Surveillance Station camera, home mode, and DSM update data',
        'safe command modeling for reboot, shutdown, Surveillance Station home mode, and camera motion detection actions represented by the snapshot',
      ],
      explicitUnsupported: [
        'homeassistant_compat shims',
        'fake Synology DSM HTTP/API login, polling, or command success without nativeClient, snapshotProvider, or commandExecutor injection',
        'full py-synologydsm-api live protocol parity in dependency-free TypeScript',
        'native camera image entity streaming because the current integration entity platform model has no camera entity type',
      ],
    },
  };

  public async setup(configArg: ISynologyDsmConfig, contextArg: IIntegrationSetupContext): Promise<IIntegrationRuntime> {
    void contextArg;
    return new SynologyDsmRuntime(new SynologyDsmClient(configArg));
  }

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

export class HomeAssistantSynologyDsmIntegration extends SynologyDsmIntegration {}

class SynologyDsmRuntime implements IIntegrationRuntime {
  public domain = synologyDsmDomain;

  constructor(private readonly client: SynologyDsmClient) {}

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

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

  public async subscribe(handlerArg: (eventArg: IIntegrationEvent) => void): Promise<() => Promise<void>> {
    const unsubscribe = this.client.onEvent((eventArg) => handlerArg({
      type: eventArg.type === 'command_failed' || eventArg.type === 'refresh_failed' ? 'error' : 'state_changed',
      integrationDomain: synologyDsmDomain,
      deviceId: eventArg.deviceId,
      entityId: eventArg.entityId,
      data: eventArg,
      timestamp: eventArg.timestamp || Date.now(),
    }));
    await this.client.getSnapshot();
    return async () => unsubscribe();
  }

  public async callService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
    if (requestArg.domain === synologyDsmDomain && (requestArg.service === 'snapshot' || requestArg.service === 'status')) {
      return { success: true, data: await this.client.getSnapshot() };
    }
    if (requestArg.domain === synologyDsmDomain && requestArg.service === 'refresh') {
      return this.client.refresh();
    }
    const snapshot = await this.client.getSnapshot();
    const command = SynologyDsmMapper.commandForService(snapshot, requestArg);
    if (!command) {
      return { success: false, error: `Unsupported Synology DSM service mapping: ${requestArg.domain}.${requestArg.service}` };
    }
    return this.client.sendCommand(command);
  }

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