import type { IConfigFlow, IConfigFlowContext, IConfigFlowStep, IDiscoveryCandidate } from '../../core/types.js';
import type { IDevoloConfig, IDevoloSnapshot } from './devolo_home_network.types.js';
import { devoloHomeNetworkDefaultPort } from './devolo_home_network.types.js';

export class DevoloHomeNetworkConfigFlow implements IConfigFlow<IDevoloConfig> {
  public async start(candidateArg: IDiscoveryCandidate, contextArg: IConfigFlowContext): Promise<IConfigFlowStep<IDevoloConfig>> {
    void contextArg;
    if (candidateArg.metadata?.homeControl === true) {
      return {
        kind: 'error',
        title: 'Unsupported devolo Home Control device',
        error: 'The devolo Home Control Central Unit is not supported by the devolo Home Network integration.',
      };
    }

    const metadata = candidateArg.metadata || {};
    const host = candidateArg.host || this.stringValue(metadata.host) || '';
    const product = candidateArg.model || this.stringValue(metadata.product) || this.stringValue(metadata.Product) || '';
    const serialNumber = candidateArg.serialNumber || candidateArg.id || this.stringValue(metadata.serialNumber) || this.stringValue(metadata.SN) || '';

    return {
      kind: 'form',
      title: 'Connect devolo Home Network device',
      description: 'Provide a local device host. Password is only used when a live native client/executor is supplied; snapshot/manual setup remains read-only until an executor is configured.',
      fields: [
        { name: 'host', label: host ? `IP address (${host})` : 'IP address', type: 'text', required: true },
        { name: 'port', label: `Port (${candidateArg.port || devoloHomeNetworkDefaultPort})`, type: 'number' },
        { name: 'password', label: 'Device password', type: 'password' },
        { name: 'name', label: candidateArg.name ? `Name (${candidateArg.name})` : 'Name', type: 'text' },
        { name: 'product', label: product ? `Product (${product})` : 'Product', type: 'text' },
        { name: 'serialNumber', label: serialNumber ? `Serial number (${serialNumber})` : 'Serial number', type: 'text' },
        { name: 'snapshotJson', label: 'Snapshot JSON', type: 'text' },
      ],
      submit: async (valuesArg) => this.submit(candidateArg, valuesArg),
    };
  }

  private async submit(candidateArg: IDiscoveryCandidate, valuesArg: Record<string, unknown>): Promise<IConfigFlowStep<IDevoloConfig>> {
    const snapshot = this.snapshotFromInput(valuesArg.snapshotJson ?? candidateArg.metadata?.snapshot);
    if (snapshot instanceof Error) {
      return { kind: 'error', title: 'Invalid snapshot', error: snapshot.message };
    }

    const host = this.stringValue(valuesArg.host) || candidateArg.host || snapshot?.device.host || snapshot?.device.ipAddress;
    if (!host && !snapshot) {
      return { kind: 'error', title: 'IP address required', error: 'devolo Home Network setup requires a host or a snapshot.' };
    }

    const metadata = candidateArg.metadata || {};
    const config: IDevoloConfig = {
      host,
      ipAddress: host,
      port: this.numberValue(valuesArg.port) || candidateArg.port || snapshot?.device.port || devoloHomeNetworkDefaultPort,
      password: this.stringValue(valuesArg.password),
      name: this.stringValue(valuesArg.name) || candidateArg.name || snapshot?.device.name,
      product: this.stringValue(valuesArg.product) || candidateArg.model || this.stringValue(metadata.product) || this.stringValue(metadata.Product) || snapshot?.device.product,
      model: candidateArg.model || this.stringValue(valuesArg.product) || snapshot?.device.model,
      serialNumber: this.stringValue(valuesArg.serialNumber) || candidateArg.serialNumber || candidateArg.id || this.stringValue(metadata.SN) || snapshot?.device.serialNumber,
      macAddress: candidateArg.macAddress || snapshot?.device.macAddress,
      mtNumber: this.stringValue(metadata.MT) || this.stringValue(metadata.mtNumber) || snapshot?.device.mtNumber,
      snapshot,
      metadata: {
        discoverySource: candidateArg.source,
        discoveryMetadata: metadata,
        liveHttpImplemented: false,
      },
    };

    return {
      kind: 'done',
      title: 'devolo Home Network device configured',
      config,
    };
  }

  private snapshotFromInput(valueArg: unknown): IDevoloSnapshot | undefined | Error {
    if (this.isRecord(valueArg)) {
      return valueArg as unknown as IDevoloSnapshot;
    }
    const text = this.stringValue(valueArg);
    if (!text) {
      return undefined;
    }
    try {
      const parsed = JSON.parse(text) as IDevoloSnapshot;
      if (!parsed || !parsed.device || !Array.isArray(parsed.plcDevices) || !Array.isArray(parsed.wifiStations)) {
        return new Error('Snapshot JSON must include device, plcDevices, and wifiStations fields.');
      }
      return parsed;
    } catch (errorArg) {
      return errorArg instanceof Error ? errorArg : new Error(String(errorArg));
    }
  }

  private stringValue(valueArg: unknown): string | undefined {
    return typeof valueArg === 'string' && valueArg.trim() ? valueArg.trim() : undefined;
  }

  private numberValue(valueArg: unknown): number | undefined {
    if (typeof valueArg === 'number' && Number.isFinite(valueArg)) {
      return valueArg;
    }
    if (typeof valueArg === 'string' && valueArg.trim()) {
      const value = Number(valueArg);
      return Number.isFinite(value) ? value : undefined;
    }
    return undefined;
  }

  private isRecord(valueArg: unknown): valueArg is Record<string, unknown> {
    return typeof valueArg === 'object' && valueArg !== null && !Array.isArray(valueArg);
  }
}

export const DevoloConfigFlow = DevoloHomeNetworkConfigFlow;
