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 { DelugeClient } from './deluge.classes.client.js';
import { DelugeConfigFlow } from './deluge.classes.configflow.js';
import { createDelugeDiscoveryDescriptor } from './deluge.discovery.js';
import { DelugeMapper } from './deluge.mapper.js';
import type { IDelugeConfig } from './deluge.types.js';
import { delugeDefaultRpcPort, delugeDefaultWebPort, delugeDisplayName, delugeDomain } from './deluge.types.js';

export class DelugeIntegration extends BaseIntegration<IDelugeConfig> {
  public readonly domain = delugeDomain;
  public readonly displayName = delugeDisplayName;
  public readonly status = 'control-runtime' as const;
  public readonly discoveryDescriptor = createDelugeDiscoveryDescriptor();
  public readonly configFlow = new DelugeConfigFlow();
  public readonly metadata = {
    source: 'home-assistant/core',
    upstreamPath: 'homeassistant/components/deluge',
    upstreamDomain: delugeDomain,
    integrationType: 'service',
    iotClass: 'local_polling',
    requirements: ['deluge-client==1.10.2'],
    dependencies: [] as string[],
    afterDependencies: [] as string[],
    codeowners: ['@tkdrob'],
    configFlow: true,
    documentation: 'https://www.home-assistant.io/integrations/deluge',
    platforms: ['sensor', 'switch'],
    discovery: {
      manual: true,
      http: `Manual/local Deluge Web JSON-RPC endpoint on port ${delugeDefaultWebPort}`,
    },
    runtime: {
      type: 'control-runtime',
      polling: 'local Deluge Web JSON-RPC snapshots at /json',
      services: ['snapshot', 'status', 'refresh', 'pause', 'resume', 'add_torrent', 'remove_torrent'],
      controls: 'Deluge Web JSON-RPC with password, or delegated to an injected client/commandExecutor',
    },
    localApi: {
      implemented: [
        'manual host/url, static snapshot/raw-data, and injected client/executor configuration',
        `Deluge Web JSON-RPC authentication against /json on port ${delugeDefaultWebPort}`,
        'web.update_ui snapshots with Home Assistant-compatible status, transfer-rate, and torrent-count sensors',
        `optional web.add_host/web.connect to a daemon on RPC port ${delugeDefaultRpcPort} when daemon credentials are provided`,
        'core.pause_torrent, core.resume_torrent, web.add_torrents/download_torrent_from_url, and core.remove_torrent controls when a live transport or executor is available',
      ],
      explicitUnsupported: [
        'raw Deluge daemon RPC without Deluge Web JSON-RPC or an injected client',
        'pretending controls succeeded for static snapshots without host/password/client/executor',
        'torrent file upload bodies; use magnet/url/server-side path or an injected executor',
      ],
    },
  };

  public async setup(configArg: IDelugeConfig, contextArg: IIntegrationSetupContext): Promise<IIntegrationRuntime> {
    void contextArg;
    return new DelugeRuntime(new DelugeClient(configArg));
  }

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

export class HomeAssistantDelugeIntegration extends DelugeIntegration {}

class DelugeRuntime implements IIntegrationRuntime {
  public domain = delugeDomain;

  constructor(private readonly client: DelugeClient) {}

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

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

  public async callService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
    try {
      const snapshot = await this.client.getSnapshot();
      const command = DelugeMapper.commandForService(snapshot, requestArg);
      if (!command) {
        return { success: false, error: `Unsupported Deluge service: ${requestArg.domain}.${requestArg.service}` };
      }
      const data = await this.client.execute(command);
      return { success: true, data };
    } catch (errorArg) {
      return { success: false, error: errorArg instanceof Error ? errorArg.message : String(errorArg) };
    }
  }

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