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 { AgentDvrClient } from './agent_dvr.classes.client.js';
import { AgentDvrConfigFlow } from './agent_dvr.classes.configflow.js';
import { createAgentDvrDiscoveryDescriptor } from './agent_dvr.discovery.js';
import { AgentDvrMapper } from './agent_dvr.mapper.js';
import type { IAgentDvrConfig } from './agent_dvr.types.js';
import { agentDvrDomain } from './agent_dvr.types.js';

export class AgentDvrIntegration extends BaseIntegration<IAgentDvrConfig> {
  public readonly domain = agentDvrDomain;
  public readonly displayName = 'Agent DVR';
  public readonly status = 'control-runtime' as const;
  public readonly discoveryDescriptor = createAgentDvrDiscoveryDescriptor();
  public readonly configFlow = new AgentDvrConfigFlow();
  public readonly metadata = {
    source: 'home-assistant/core',
    upstreamPath: 'homeassistant/components/agent_dvr',
    upstreamDomain: agentDvrDomain,
    integrationType: 'hub',
    iotClass: 'local_polling',
    requirements: ['agent-py==0.0.24'],
    dependencies: [] as string[],
    afterDependencies: [] as string[],
    codeowners: ['@ispysoftware'],
    documentation: 'https://www.home-assistant.io/integrations/agent_dvr',
    configFlow: true,
    nativePort: {
      manualLocalDiscovery: true,
      mdnsMetadataMatching: true,
      ssdpMetadataMatching: true,
      localHttpApi: true,
      cameraSnapshotMapping: true,
      cameraMjpegUrlMapping: true,
      liveEventSubscription: false,
      videoProxying: false,
    },
    localApi: {
      implemented: [
        'manual/local host config flow using the Agent DVR HTTP API default port 8090',
        'command.cgi getStatus, getObjects, getObject-shaped snapshot normalization where the local API exposes it',
        'camera still image and MJPEG URL mapping through grab.jpg and video.mjpg',
        'Agent DVR camera services for alerts, recording, snapshots, camera on/off, and motion detector commands through command.cgi',
        'alarm panel arm/disarm/profile commands represented by the Home Assistant integration',
      ],
      explicitUnsupported: [
        'Agent DVR cloud or remote portal APIs',
        'live video proxying/transcoding and live event subscriptions',
        'claiming command success without a configured local HTTP endpoint, injected client, or command executor',
      ],
    },
  };

  public async setup(configArg: IAgentDvrConfig, contextArg: IIntegrationSetupContext): Promise<IIntegrationRuntime> {
    void contextArg;
    return new AgentDvrRuntime(new AgentDvrClient(configArg));
  }

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

export class HomeAssistantAgentDvrIntegration extends AgentDvrIntegration {}

class AgentDvrRuntime implements IIntegrationRuntime {
  public domain = agentDvrDomain;

  constructor(private readonly client: AgentDvrClient) {}

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

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

  public async subscribe(handlerArg: (eventArg: IIntegrationEvent) => void): Promise<() => Promise<void>> {
    void handlerArg;
    throw new Error('Agent DVR live event subscription is not implemented in this TypeScript port; use polling or explicit refreshes.');
  }

  public async callService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
    try {
      const snapshot = await this.client.getSnapshot();
      const command = AgentDvrMapper.commandForService(snapshot, requestArg);
      if (!command) {
        return { success: false, error: `Unsupported Agent DVR service or target: ${requestArg.domain}.${requestArg.service}` };
      }
      const data = await this.client.execute(command);
      const success = this.successFromResult(data);
      return { success, error: success ? undefined : 'Agent DVR command reported failure.', data };
    } catch (errorArg) {
      return { success: false, error: errorArg instanceof Error ? errorArg.message : String(errorArg) };
    }
  }

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

  private successFromResult(valueArg: unknown): boolean {
    if (valueArg && typeof valueArg === 'object') {
      const record = valueArg as Record<string, unknown>;
      if (typeof record.success === 'boolean') {
        return record.success;
      }
      if (typeof record.ok === 'boolean') {
        return record.ok;
      }
    }
    return true;
  }
}
