import type { IConfigFlow, IConfigFlowContext, IConfigFlowStep, IDiscoveryCandidate } from '../../core/types.js';
import type { IHikvisionConfig, THikvisionAuthScheme, THikvisionProtocol } from './hikvision.types.js';
import { hikvisionDefaultPort, hikvisionDefaultRtspPort, hikvisionDefaultTimeoutMs } from './hikvision.types.js';

export class HikvisionConfigFlow implements IConfigFlow<IHikvisionConfig> {
  public async start(candidateArg: IDiscoveryCandidate, contextArg: IConfigFlowContext): Promise<IConfigFlowStep<IHikvisionConfig>> {
    void contextArg;
    return {
      kind: 'form',
      title: 'Connect Hikvision device',
      description: 'Configure the local Hikvision ISAPI endpoint for a camera or NVR.',
      fields: [
        { name: 'protocol', label: 'Protocol', type: 'select', required: true, options: [{ label: 'HTTP', value: 'http' }, { label: 'HTTPS', value: 'https' }] },
        { name: 'host', label: 'Host', type: 'text', required: true },
        { name: 'port', label: 'Port', type: 'number', required: true },
        { name: 'username', label: 'Username', type: 'text', required: true },
        { name: 'password', label: 'Password', type: 'password', required: true },
        { name: 'authScheme', label: 'Authentication', type: 'select', options: [{ label: 'Auto', value: 'auto' }, { label: 'Basic', value: 'basic' }, { label: 'Digest', value: 'digest' }] },
        { name: 'name', label: 'Name', type: 'text' },
      ],
      submit: async (valuesArg) => {
        const protocol = this.protocolValue(valuesArg.protocol) || this.protocolMetadata(candidateArg) || 'http';
        const host = this.stringValue(valuesArg.host) || candidateArg.host;
        if (!host) {
          return { kind: 'error', error: 'Hikvision requires a host.' };
        }
        const port = this.numberValue(valuesArg.port) || candidateArg.port || (protocol === 'https' ? 443 : hikvisionDefaultPort);
        if (!Number.isInteger(port) || port < 1 || port > 65535) {
          return { kind: 'error', error: 'Hikvision requires a valid TCP port.' };
        }
        const username = this.stringValue(valuesArg.username) || this.stringMetadata(candidateArg, 'username');
        const password = this.stringValue(valuesArg.password) || this.stringMetadata(candidateArg, 'password');
        if (!username || password === undefined) {
          return { kind: 'error', error: 'Hikvision requires username and password.' };
        }
        return {
          kind: 'done',
          title: 'Hikvision device configured',
          config: {
            protocol,
            ssl: protocol === 'https',
            host,
            port,
            rtspPort: hikvisionDefaultRtspPort,
            username,
            password,
            authScheme: this.authSchemeValue(valuesArg.authScheme) || 'auto',
            name: this.stringValue(valuesArg.name) || candidateArg.name || host,
            uniqueId: candidateArg.id || candidateArg.macAddress || candidateArg.serialNumber || host,
            model: candidateArg.model,
            deviceType: this.stringMetadata(candidateArg, 'deviceType'),
            timeoutMs: hikvisionDefaultTimeoutMs,
            snapshot: this.snapshotMetadata(candidateArg),
          },
        };
      },
    };
  }

  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 stringMetadata(candidateArg: IDiscoveryCandidate, keyArg: string): string | undefined {
    const value = candidateArg.metadata?.[keyArg];
    return typeof value === 'string' && value.trim() ? value.trim() : undefined;
  }

  private snapshotMetadata(candidateArg: IDiscoveryCandidate): IHikvisionConfig['snapshot'] | undefined {
    const snapshot = candidateArg.metadata?.snapshot;
    return snapshot && typeof snapshot === 'object' ? snapshot as IHikvisionConfig['snapshot'] : undefined;
  }

  private protocolMetadata(candidateArg: IDiscoveryCandidate): THikvisionProtocol | undefined {
    const protocol = candidateArg.metadata?.protocol;
    if (protocol === 'http' || protocol === 'https') {
      return protocol;
    }
    return candidateArg.metadata?.ssl === true ? 'https' : undefined;
  }

  private protocolValue(valueArg: unknown): THikvisionProtocol | undefined {
    return valueArg === 'http' || valueArg === 'https' ? valueArg : undefined;
  }

  private authSchemeValue(valueArg: unknown): THikvisionAuthScheme | undefined {
    return valueArg === 'auto' || valueArg === 'basic' || valueArg === 'digest' ? valueArg : undefined;
  }
}
