import type { IConfigFlow, IConfigFlowContext, IConfigFlowStep, IDiscoveryCandidate } from '../../core/types.js';
import type { IZhaConfig, IZhaSnapshot, TZhaFlowControl, TZhaRadioType } from './zha.types.js';

const radioTypeOptions: Array<{ label: string; value: string }> = [
  { label: 'Silicon Labs EZSP / EmberZNet', value: 'ezsp' },
  { label: 'TI Z-Stack (ZNP)', value: 'znp' },
  { label: 'deCONZ / ConBee', value: 'deconz' },
  { label: 'XBee', value: 'xbee' },
  { label: 'ZiGate', value: 'zigate' },
];

export class ZhaConfigFlow implements IConfigFlow<IZhaConfig> {
  public async start(candidateArg: IDiscoveryCandidate, contextArg: IConfigFlowContext): Promise<IConfigFlowStep<IZhaConfig>> {
    void contextArg;
    const defaults = this.defaultsFromCandidate(candidateArg);
    return {
      kind: 'form',
      title: 'Connect Zigbee Home Automation',
      description: 'Configure the ZHA radio path and optional snapshot data. Live Zigbee radio probing is not performed by this TypeScript port.',
      fields: [
        { name: 'radioPath', label: 'Radio path or socket URL', type: 'text', required: true },
        { name: 'radioType', label: 'Radio type', type: 'select', required: true, options: radioTypeOptions },
        { name: 'baudrate', label: 'Baudrate', type: 'number' },
        { name: 'flowControl', label: 'Flow control', type: 'select', options: [{ label: 'None', value: 'none' }, { label: 'Hardware', value: 'hardware' }, { label: 'Software', value: 'software' }] },
        { name: 'databasePath', label: 'Zigpy database path', type: 'text' },
        { name: 'enableQuirks', label: 'Enable ZHA quirks', type: 'boolean' },
        { name: 'snapshotJson', label: 'Snapshot JSON', type: 'text' },
      ],
      submit: async (valuesArg) => {
        const snapshot = this.snapshotValue(valuesArg.snapshotJson, defaults.snapshot);
        if (snapshot === false) {
          return { kind: 'error', title: 'Invalid ZHA snapshot', error: 'Snapshot JSON must be a JSON object.' };
        }
        const radioPath = this.stringValue(valuesArg.radioPath) || defaults.radioPath || '/dev/ttyUSB0';
        const radioType = this.stringValue(valuesArg.radioType) || defaults.radioType || 'znp';
        const baudrate = this.numberValue(valuesArg.baudrate) || defaults.baudrate || 115200;
        const flowControl = this.flowControlValue(valuesArg.flowControl) ?? defaults.flowControl ?? 'none';
        return {
          kind: 'done',
          title: 'ZHA configured',
          config: {
            radio: {
              path: radioPath,
              radioType,
              baudrate,
              flowControl,
              socketUrl: radioPath.startsWith('socket://') ? radioPath : undefined,
            },
            device: {
              path: radioPath,
              baudrate,
              flow_control: flowControl === 'none' ? null : flowControl,
            },
            radioType,
            radio_type: radioType,
            databasePath: this.stringValue(valuesArg.databasePath) || defaults.databasePath,
            enableQuirks: this.booleanValue(valuesArg.enableQuirks) ?? true,
            snapshot: snapshot || undefined,
          },
        };
      },
    };
  }

  private defaultsFromCandidate(candidateArg: IDiscoveryCandidate): { radioPath?: string; radioType?: TZhaRadioType; baudrate?: number; flowControl?: TZhaFlowControl; databasePath?: string; snapshot?: IZhaSnapshot } {
    const metadata = candidateArg.metadata || {};
    return {
      radioPath: this.stringValue(metadata.radioPath) || this.stringValue(metadata.socketUrl) || this.stringValue(metadata.path) || (candidateArg.host ? `socket://${candidateArg.host}:${candidateArg.port || 6638}` : undefined),
      radioType: this.stringValue(metadata.radioType),
      baudrate: this.numberValue(metadata.baudrate),
      flowControl: this.flowControlValue(metadata.flowControl),
      databasePath: this.stringValue(metadata.databasePath),
      snapshot: this.isSnapshot(metadata.snapshot) ? metadata.snapshot : undefined,
    };
  }

  private snapshotValue(valueArg: unknown, fallbackArg?: IZhaSnapshot): IZhaSnapshot | undefined | false {
    if (valueArg === undefined || valueArg === null || valueArg === '') {
      return fallbackArg;
    }
    if (this.isSnapshot(valueArg)) {
      return valueArg;
    }
    if (typeof valueArg !== 'string') {
      return false;
    }
    try {
      const parsed = JSON.parse(valueArg) as unknown;
      return this.isRecord(parsed) ? parsed as unknown as IZhaSnapshot : false;
    } catch {
      return false;
    }
  }

  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 : undefined;
  }

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

  private flowControlValue(valueArg: unknown): TZhaFlowControl | undefined {
    if (valueArg === null || valueArg === 'none' || valueArg === 'hardware' || valueArg === 'software') {
      return valueArg;
    }
    return undefined;
  }

  private isSnapshot(valueArg: unknown): valueArg is IZhaSnapshot {
    return this.isRecord(valueArg);
  }

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