import type { IConfigFlow, IConfigFlowContext, IConfigFlowStep, IDiscoveryCandidate } from '../../core/types.js';
import type { ILinkplayConfig, TLinkplayProtocol } from './linkplay.types.js';
import { linkplayDefaultPort } from './linkplay.types.js';

export class LinkplayConfigFlow implements IConfigFlow<ILinkplayConfig> {
  public async start(candidateArg: IDiscoveryCandidate, contextArg: IConfigFlowContext): Promise<IConfigFlowStep<ILinkplayConfig>> {
    void contextArg;
    return {
      kind: 'form',
      title: 'Connect LinkPlay',
      description: candidateArg.source === 'manual'
        ? 'Configure a local LinkPlay HTTP API endpoint.'
        : 'Confirm or adjust the discovered local LinkPlay endpoint.',
      fields: [
        { name: 'host', label: 'Host', type: 'text', required: true },
        { name: 'port', label: 'HTTP API port', type: 'number' },
        { name: 'protocol', label: 'Protocol', type: 'select', options: [{ label: 'HTTP', value: 'http' }, { label: 'HTTPS', value: 'https' }] },
        { name: 'name', label: 'Name', type: 'text' },
      ],
      submit: async (valuesArg) => {
        if (isWiimCandidate(candidateArg)) {
          return { kind: 'error', title: 'LinkPlay setup failed', error: 'This device should be set up with the WiiM integration.' };
        }
        const host = stringValue(valuesArg.host) || candidateArg.host;
        if (!host) {
          return { kind: 'error', title: 'LinkPlay setup failed', error: 'LinkPlay host is required.' };
        }
        const protocol = protocolValue(valuesArg.protocol) || protocolMetadata(candidateArg) || protocolFromPort(candidateArg.port);
        const port = numberValue(valuesArg.port) || candidateArg.port || defaultPort(protocol);
        return {
          kind: 'done',
          title: 'LinkPlay configured',
          config: {
            host,
            port,
            protocol,
            name: stringValue(valuesArg.name) || candidateArg.name,
            uniqueId: candidateArg.id,
            manufacturer: candidateArg.manufacturer,
            model: candidateArg.model,
            modelId: stringMetadata(candidateArg.metadata?.modelId),
            macAddress: candidateArg.macAddress,
          },
        };
      },
    };
  }
}

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

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

const protocolValue = (valueArg: unknown): TLinkplayProtocol | undefined => {
  return valueArg === 'http' || valueArg === 'https' ? valueArg : undefined;
};

const protocolMetadata = (candidateArg: IDiscoveryCandidate): TLinkplayProtocol | undefined => protocolValue(candidateArg.metadata?.protocol);

const protocolFromPort = (portArg: number | undefined): TLinkplayProtocol => portArg === 443 || portArg === 4443 ? 'https' : 'http';

const defaultPort = (protocolArg: TLinkplayProtocol): number => protocolArg === 'https' ? 443 : linkplayDefaultPort;

const stringMetadata = (valueArg: unknown): string | undefined => typeof valueArg === 'string' ? valueArg : undefined;

const isWiimCandidate = (candidateArg: IDiscoveryCandidate): boolean => {
  const haystack = `${candidateArg.manufacturer || ''} ${candidateArg.model || ''} ${stringMetadata(candidateArg.metadata?.project) || ''}`.toLowerCase();
  return haystack.includes('wiim') || haystack.includes('muzo_mini');
};
