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 { ElgatoClient } from './elgato.classes.client.js';
import { ElgatoConfigFlow } from './elgato.classes.configflow.js';
import { createElgatoDiscoveryDescriptor } from './elgato.discovery.js';
import { ElgatoMapper } from './elgato.mapper.js';
import type { IElgatoConfig } from './elgato.types.js';
import { elgatoDefaultPort, elgatoDisplayName, elgatoDomain, elgatoZeroconfType } from './elgato.types.js';

export class ElgatoIntegration extends BaseIntegration<IElgatoConfig> {
  public readonly domain = elgatoDomain;
  public readonly displayName = elgatoDisplayName;
  public readonly status = 'control-runtime' as const;
  public readonly discoveryDescriptor = createElgatoDiscoveryDescriptor();
  public readonly configFlow = new ElgatoConfigFlow();
  public readonly metadata = {
    source: 'home-assistant/core',
    upstreamPath: 'homeassistant/components/elgato',
    upstreamDomain: elgatoDomain,
    integrationType: 'device',
    iotClass: 'local_polling',
    qualityScale: 'platinum',
    requirements: ['elgato==5.1.2'],
    dependencies: [] as string[],
    afterDependencies: [] as string[],
    codeowners: ['@frenck'],
    configFlow: true,
    documentation: 'https://www.home-assistant.io/integrations/elgato',
    dhcp: [{ registered_devices: true }],
    zeroconf: [elgatoZeroconfType],
    discovery: {
      zeroconf: elgatoZeroconfType,
      dhcp: 'DHCP registered-device candidates and obvious Elgato/Key Light hostnames are recognized for local host updates.',
      manual: true,
    },
    runtime: {
      type: 'control-runtime',
      polling: `local HTTP Elgato Light API on port ${elgatoDefaultPort}: /elgato/accessory-info, /elgato/lights/settings, /elgato/lights, and /elgato/battery-info`,
      services: ['snapshot', 'status', 'refresh', 'light.turn_on', 'light.turn_off', 'identify', 'restart', 'battery_bypass', 'energy_saving'],
      controls: true,
    },
    localApi: {
      implemented: [
        'Elgato local HTTP accessory-info/settings/lights/battery-info snapshots compatible with the upstream elgato==5.1.2 client',
        'PUT /elgato/lights commands for on/off, brightness, color temperature, and HS color',
        'POST /elgato/identify and /elgato/restart button commands',
        'zeroconf, DHCP, and manual discovery plus config-flow output for local HTTP setup',
        'snapshot/manual-data and injected client/executor operation',
      ],
      explicitUnsupported: [
        'cloud or Stream Deck account APIs',
        'fake live command success without a configured HTTP endpoint, injected client, or command executor',
      ],
    },
  };

  public async setup(configArg: IElgatoConfig, contextArg: IIntegrationSetupContext): Promise<IIntegrationRuntime> {
    void contextArg;
    return new ElgatoRuntime(new ElgatoClient(configArg));
  }

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

export class HomeAssistantElgatoIntegration extends ElgatoIntegration {}

class ElgatoRuntime implements IIntegrationRuntime {
  public domain = elgatoDomain;

  constructor(private readonly client: ElgatoClient) {}

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

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

  public async callService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
    try {
      if (requestArg.domain === elgatoDomain && (requestArg.service === 'snapshot' || requestArg.service === 'status')) {
        const snapshot = await this.client.getSnapshot();
        return { success: true, data: requestArg.service === 'status' ? snapshot.light : snapshot };
      }
      if (requestArg.domain === elgatoDomain && requestArg.service === 'refresh') {
        const result = await this.client.refresh();
        return { success: result.success, error: result.error, data: result.snapshot || result.data };
      }

      const snapshot = await this.client.getSnapshot();
      const command = ElgatoMapper.commandForService(snapshot, requestArg);
      if (!command) {
        return { success: false, error: `Unsupported Elgato service: ${requestArg.domain}.${requestArg.service}` };
      }
      const data = await this.client.execute(command);
      const ok = data && typeof data === 'object' && 'ok' in data ? Boolean((data as { ok?: unknown }).ok) : true;
      return { success: ok, data };
    } catch (errorArg) {
      return { success: false, error: errorArg instanceof Error ? errorArg.message : String(errorArg) };
    }
  }

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