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 { GoodweClient } from './goodwe.classes.client.js';
import { GoodweConfigFlow } from './goodwe.classes.configflow.js';
import { createGoodweDiscoveryDescriptor } from './goodwe.discovery.js';
import { GoodweMapper } from './goodwe.mapper.js';
import type { IGoodweConfig } from './goodwe.types.js';
import { goodweDefaultTcpPort, goodweDefaultUdpPort, goodweDisplayName, goodweDomain } from './goodwe.types.js';

export class GoodweIntegration extends BaseIntegration<IGoodweConfig> {
  public readonly domain = goodweDomain;
  public readonly displayName = goodweDisplayName;
  public readonly status = 'read-only-runtime' as const;
  public readonly discoveryDescriptor = createGoodweDiscoveryDescriptor();
  public readonly configFlow = new GoodweConfigFlow();
  public readonly metadata = {
    source: 'home-assistant/core',
    upstreamPath: 'homeassistant/components/goodwe',
    upstreamDomain: goodweDomain,
    integrationType: 'device',
    iotClass: 'local_polling',
    requirements: ['goodwe==0.4.10'],
    dependencies: [] as string[],
    afterDependencies: [] as string[],
    codeowners: ['@mletenay', '@starkillerOG'],
    configFlow: true,
    documentation: 'https://www.home-assistant.io/integrations/goodwe',
    platforms: ['button', 'number', 'select', 'sensor'],
    defaults: {
      udpPort: goodweDefaultUdpPort,
      tcpFallbackPort: goodweDefaultTcpPort,
      scanIntervalSeconds: 10,
    },
    discovery: {
      manual: true,
      upstreamManifestDiscovery: 'none; Home Assistant config flow asks for a host and probes UDP 8899 then TCP 502 through goodwe==0.4.10',
    },
    runtime: {
      type: 'read-only-runtime',
      polling: 'manual snapshots, raw runtime data, or injected GoodWe client snapshots',
      services: ['snapshot', 'status', 'refresh', 'set_operation_mode', 'set_grid_export_limit', 'set_battery_discharge_depth', 'synchronize_clock', 'write_setting', 'read_setting'],
      controls: 'delegated only to an injected client.execute or commandExecutor',
    },
    localApi: {
      implemented: [
        'manual host/snapshot/raw-data/injected-client configuration',
        'GoodWe runtime snapshot normalization from read_runtime_data-style dictionaries',
        'sensor, select, number, and button entity modeling from Home Assistant GoodWe platforms',
        'read/control delegation to injected client or commandExecutor',
      ],
      explicitUnsupported: [
        'native GoodWe UDP AA55/Modbus protocol transport in this TypeScript package',
        'broadcast inverter scan on UDP 48899',
        'pretending a host-only UDP/TCP inverter refresh or write succeeded without an injected protocol client/executor',
      ],
    },
  };

  public async setup(configArg: IGoodweConfig, contextArg: IIntegrationSetupContext): Promise<IIntegrationRuntime> {
    void contextArg;
    return new GoodweRuntime(new GoodweClient(configArg));
  }

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

export class HomeAssistantGoodweIntegration extends GoodweIntegration {}

class GoodweRuntime implements IIntegrationRuntime {
  public domain = goodweDomain;

  constructor(private readonly client: GoodweClient) {}

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

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

  public async callService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
    try {
      if (requestArg.domain === goodweDomain && (requestArg.service === 'snapshot' || requestArg.service === 'status')) {
        return { success: true, data: await this.client.getSnapshot() };
      }
      if (requestArg.domain === goodweDomain && 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 = GoodweMapper.commandForService(snapshot, requestArg);
      if (!command) {
        return { success: false, error: `Unsupported GoodWe service or target: ${requestArg.domain}.${requestArg.service}` };
      }
      const data = await this.client.execute(command);
      return { success: true, data: data ?? command };
    } catch (errorArg) {
      return { success: false, error: errorArg instanceof Error ? errorArg.message : String(errorArg) };
    }
  }

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