import type * as shxInterfaces from '@smarthome.exchange/interfaces';
import { SimpleLocalIntegration } from '../../core/index.js';
import type { IIntegrationEntity, IIntegrationRuntime, IIntegrationSetupContext, IServiceCallRequest, IServiceCallResult } from '../../core/index.js';
import { NutClient } from './nut.classes.client.js';
import { NutConfigFlow } from './nut.classes.configflow.js';
import { createNutDiscoveryDescriptor } from './nut.discovery.js';
import { NutMapper } from './nut.mapper.js';
import type { INutConfig } from './nut.types.js';
import { nutDomain, nutProfile } from './nut.types.js';

export class NutIntegration extends SimpleLocalIntegration<INutConfig> {
  public readonly domain = nutDomain;
  public readonly discoveryDescriptor = createNutDiscoveryDescriptor();
  public readonly configFlow = new NutConfigFlow();

  constructor() {
    super(nutProfile);
  }

  public async setup(configArg: INutConfig, contextArg: IIntegrationSetupContext): Promise<IIntegrationRuntime> {
    void contextArg;
    return new NutRuntime(new NutClient(configArg));
  }
}

export class HomeAssistantNutIntegration extends NutIntegration {}

class NutRuntime implements IIntegrationRuntime {
  public domain = nutDomain;

  constructor(private readonly client: NutClient) {}

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

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

  public async callService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
    if (!this.acceptsDomain(requestArg.domain)) {
      return { success: false, error: `Unsupported Network UPS Tools (NUT) service domain: ${requestArg.domain}` };
    }
    if (requestArg.service === 'snapshot' || requestArg.service === 'status') {
      return { success: true, data: await this.client.getSnapshot() };
    }
    if (requestArg.service === 'refresh' || requestArg.service === 'reload') {
      return this.client.refresh();
    }
    return this.client.execute(requestArg);
  }

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

  private acceptsDomain(domainArg: string): boolean {
    return domainArg === nutDomain || domainArg === 'button' || domainArg === 'switch';
  }
}
