import type { IConfigFlow, IConfigFlowContext, IConfigFlowStep, IDiscoveryCandidate } from '../../core/types.js';
import type { IVelbusConfig, IVelbusGatewayConfig, TVelbusGatewayConnection } from './velbus.types.js';

export class VelbusConfigFlow implements IConfigFlow<IVelbusConfig> {
  public async start(candidateArg: IDiscoveryCandidate, contextArg: IConfigFlowContext): Promise<IConfigFlowStep<IVelbusConfig>> {
    void contextArg;
    const metadata = candidateArg.metadata || {};
    const connection = metadata.connection === 'serial' || metadata.connection === 'tcp' ? metadata.connection : candidateArg.host ? 'tcp' : 'serial';
    return {
      kind: 'form',
      title: connection === 'tcp' ? 'Connect Velbus TCP/IP Gateway' : 'Connect Velbus Serial Gateway',
      description: 'Configure the Velbus gateway DSN. VLP import is represented as an optional file path; live bus framing is not implemented by this TypeScript runtime.',
      fields: [
        { name: 'connection', label: 'Connection', type: 'select', required: true, options: [{ label: 'Serial/USB', value: 'serial' }, { label: 'TCP/IP', value: 'tcp' }] },
        { name: 'serialPath', label: 'Serial path', type: 'text', required: false },
        { name: 'host', label: 'Host', type: 'text', required: false },
        { name: 'port', label: 'Port', type: 'number', required: false },
        { name: 'tls', label: 'Use TLS', type: 'boolean', required: false },
        { name: 'password', label: 'Password', type: 'password', required: false },
        { name: 'vlpFile', label: 'VLP file path', type: 'text', required: false },
      ],
      submit: async (valuesArg) => {
        const selectedConnection = connectionValue(valuesArg.connection) || connection;
        const gateway = gatewayFromValues(selectedConnection, candidateArg, valuesArg);
        return {
          kind: 'done',
          title: 'Velbus gateway configured',
          config: {
            gateway,
            mutationMode: 'manual-snapshot',
          },
        };
      },
    };
  }
}

const gatewayFromValues = (connectionArg: TVelbusGatewayConnection, candidateArg: IDiscoveryCandidate, valuesArg: Record<string, unknown>): IVelbusGatewayConfig => {
  const metadata = candidateArg.metadata || {};
  const serialPath = stringValue(valuesArg.serialPath) || stringValue(metadata.serialPath) || stringValue(metadata.dsn);
  const host = stringValue(valuesArg.host) || candidateArg.host;
  const tls = booleanValue(valuesArg.tls, metadata.tls !== false);
  const port = numberValue(valuesArg.port) || candidateArg.port || (tls ? 27015 : 6000);
  const password = stringValue(valuesArg.password) || stringValue(metadata.password);
  const vlpFile = stringValue(valuesArg.vlpFile) || stringValue(metadata.vlpFile);
  return {
    id: candidateArg.id,
    name: candidateArg.name,
    connection: connectionArg,
    dsn: connectionArg === 'tcp' ? dsnFromTcp(host, port, tls, password) : serialPath,
    serialPath: connectionArg === 'serial' ? serialPath : undefined,
    host: connectionArg === 'tcp' ? host : undefined,
    port: connectionArg === 'tcp' ? port : undefined,
    tls: connectionArg === 'tcp' ? tls : undefined,
    password: connectionArg === 'tcp' ? password : undefined,
    vlpFile,
    manufacturer: candidateArg.manufacturer || 'Velleman',
    model: candidateArg.model,
    serialNumber: candidateArg.serialNumber,
  };
};

const connectionValue = (valueArg: unknown): TVelbusGatewayConnection | undefined => valueArg === 'serial' || valueArg === 'tcp' ? valueArg : undefined;

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

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

const booleanValue = (valueArg: unknown, defaultArg: boolean): boolean => typeof valueArg === 'boolean' ? valueArg : defaultArg;

const dsnFromTcp = (hostArg: string | undefined, portArg: number | undefined, tlsArg: boolean, passwordArg: string | undefined): string | undefined => {
  if (!hostArg || !portArg) {
    return undefined;
  }
  const credentials = passwordArg ? `${passwordArg}@` : '';
  return `${tlsArg ? 'tls://' : ''}${credentials}${hostArg}:${portArg}`;
};
