import type { IConfigFlow, IConfigFlowContext, IConfigFlowStep, IDiscoveryCandidate } from '../../core/types.js';
import { dsmrRfxtrxProtocol, dsmrVersions } from './dsmr.constants.js';
import type { IDsmrConfig, TDsmrConnectionType } from './dsmr.types.js';
import { dsmrDefaultNetworkPort } from './dsmr.types.js';

export class DsmrConfigFlow implements IConfigFlow<IDsmrConfig> {
  public async start(candidateArg: IDiscoveryCandidate, contextArg: IConfigFlowContext): Promise<IConfigFlowStep<IDsmrConfig>> {
    void contextArg;
    return {
      kind: 'form',
      title: 'Connect DSMR smart meter',
      description: 'Configure a known DSMR/P1 serial port or network-to-P1 endpoint. The flow validates configuration shape only and does not claim live hardware success.',
      fields: [
        { name: 'connectionType', label: 'Connection type', type: 'select', required: true, options: [{ label: 'Serial', value: 'serial' }, { label: 'Network', value: 'network' }] },
        { name: 'serialPort', label: 'Serial port path', type: 'text' },
        { name: 'host', label: 'Network host', type: 'text' },
        { name: 'port', label: 'Network port', type: 'number' },
        { name: 'dsmrVersion', label: 'DSMR version', type: 'select', required: true, options: dsmrVersions.map((versionArg) => ({ label: versionArg, value: versionArg })) },
        { name: 'protocol', label: 'Protocol', type: 'select', required: false, options: [{ label: 'DSMR', value: 'dsmr_protocol' }, { label: 'RFXtrx DSMR', value: dsmrRfxtrxProtocol }] },
        { name: 'liveRead', label: 'Read telegrams from network on refresh', type: 'boolean' },
      ],
      submit: async (valuesArg) => {
        const connectionType = this.connectionType(valuesArg.connectionType) || this.connectionType(candidateArg.metadata?.connectionType) || (candidateArg.host ? 'network' : 'serial');
        const serialPort = this.stringValue(valuesArg.serialPort) || this.stringValue(candidateArg.metadata?.serialPort);
        const host = this.stringValue(valuesArg.host) || candidateArg.host;
        const port = this.numberValue(valuesArg.port) || candidateArg.port || dsmrDefaultNetworkPort;
        const dsmrVersion = this.dsmrVersion(valuesArg.dsmrVersion) || this.dsmrVersion(candidateArg.metadata?.dsmrVersion) || this.dsmrVersion(candidateArg.metadata?.dsmr_version) || '2.2';
        const protocol = this.protocol(valuesArg.protocol) || this.protocol(candidateArg.metadata?.protocol) || 'dsmr_protocol';

        if (connectionType === 'network' && (!host || !port)) {
          return { kind: 'error', title: 'DSMR configuration failed', error: 'Network DSMR setup requires host and port.' };
        }
        if (connectionType === 'serial' && !serialPort) {
          return { kind: 'error', title: 'DSMR configuration failed', error: 'Serial DSMR setup requires a serial port path.' };
        }

        return {
          kind: 'done',
          title: 'DSMR meter configured',
          config: {
            id: candidateArg.id || this.slug(host || serialPort || 'dsmr_meter'),
            name: candidateArg.name || 'DSMR Smart Meter',
            connectionType,
            host: connectionType === 'network' ? host : undefined,
            port: connectionType === 'network' ? port : serialPort,
            serialPort: connectionType === 'serial' ? serialPort : undefined,
            dsmrVersion,
            dsmr_version: dsmrVersion,
            protocol,
            connected: false,
            liveRead: connectionType === 'network' ? this.booleanValue(valuesArg.liveRead) ?? false : false,
          },
        };
      },
    };
  }

  private connectionType(valueArg: unknown): TDsmrConnectionType | undefined {
    return valueArg === 'serial' || valueArg === 'network' ? valueArg : undefined;
  }

  private dsmrVersion(valueArg: unknown): string | undefined {
    return typeof valueArg === 'string' && (dsmrVersions as string[]).includes(valueArg) ? valueArg : undefined;
  }

  private protocol(valueArg: unknown): 'dsmr_protocol' | 'rfxtrx_dsmr_protocol' | undefined {
    return valueArg === 'dsmr_protocol' || valueArg === 'rfxtrx_dsmr_protocol' ? valueArg : undefined;
  }

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

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

  private booleanValue(valueArg: unknown): boolean | undefined {
    return typeof valueArg === 'boolean' ? valueArg : undefined;
  }

  private slug(valueArg: string): string {
    return valueArg.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '') || 'dsmr_meter';
  }
}
