import type { IConfigFlow, IConfigFlowContext, IConfigFlowStep, IDiscoveryCandidate } from '../../core/types.js';
import type { IHarmanKardonAvrConfig, IHarmanKardonAvrSnapshot } from './harman_kardon_avr.types.js';
import { harmanKardonAvrDefaultName, harmanKardonAvrDefaultPort } from './harman_kardon_avr.types.js';

export class HarmanKardonAvrConfigFlow implements IConfigFlow<IHarmanKardonAvrConfig> {
  public async start(candidateArg: IDiscoveryCandidate, contextArg: IConfigFlowContext): Promise<IConfigFlowStep<IHarmanKardonAvrConfig>> {
    void contextArg;
    const metadata = candidateArg.metadata || {};
    const snapshot = snapshotMetadata(metadata);
    const hasInjectedRuntime = Boolean(snapshot || metadata.client || metadata.commandExecutor);
    return {
      kind: 'form',
      title: 'Connect Harman Kardon AVR',
      description: hasInjectedRuntime
        ? 'Configure the AVR using the discovered snapshot or injected runtime.'
        : 'Configure the local Harman Kardon/JBL AVR TCP endpoint.',
      fields: [
        { name: 'host', label: 'Host', type: 'text', required: !hasInjectedRuntime },
        { name: 'port', label: 'TCP port', type: 'number' },
        { name: 'name', label: 'Name', type: 'text' },
        { name: 'model', label: 'Model', type: 'text' },
      ],
      submit: async (valuesArg) => {
        const host = stringValue(valuesArg.host) || candidateArg.host || snapshot?.deviceInfo.host;
        if (!host && !hasInjectedRuntime) {
          return { kind: 'error', error: 'Harman Kardon AVR setup requires a host, snapshot, injected client, or commandExecutor.' };
        }
        return {
          kind: 'done',
          title: 'Harman Kardon AVR configured',
          config: {
            host,
            port: numberValue(valuesArg.port) || candidateArg.port || snapshot?.deviceInfo.port || harmanKardonAvrDefaultPort,
            name: stringValue(valuesArg.name) || candidateArg.name || snapshot?.deviceInfo.name || harmanKardonAvrDefaultName,
            manufacturer: candidateArg.manufacturer || snapshot?.deviceInfo.manufacturer || 'Harman Kardon',
            model: stringValue(valuesArg.model) || candidateArg.model || snapshot?.deviceInfo.model,
            serialNumber: candidateArg.serialNumber || snapshot?.deviceInfo.serialNumber,
            zone: stringValue(metadata.zone) || snapshot?.deviceInfo.zone,
            sources: stringArrayValue(metadata.sources) || snapshot?.state.sourceList,
            state: metadata.state as IHarmanKardonAvrConfig['state'],
            snapshot,
            client: metadata.client as IHarmanKardonAvrConfig['client'],
            commandExecutor: metadata.commandExecutor as IHarmanKardonAvrConfig['commandExecutor'],
          },
        };
      },
    };
  }
}

const snapshotMetadata = (metadataArg: Record<string, unknown>): IHarmanKardonAvrSnapshot | undefined => {
  const snapshot = metadataArg.snapshot;
  return snapshot && typeof snapshot === 'object' && 'deviceInfo' in snapshot && 'state' in snapshot
    ? snapshot as IHarmanKardonAvrSnapshot
    : undefined;
};

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

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

const stringArrayValue = (valueArg: unknown): string[] | undefined => {
  return Array.isArray(valueArg) && valueArg.every((itemArg) => typeof itemArg === 'string') ? valueArg : undefined;
};
