import { DiscoveryDescriptor } from '../../core/classes.discoverydescriptor.js';
import type { IDiscoveryCandidate, IDiscoveryMatch, IDiscoveryMatcher, IDiscoveryValidator } from '../../core/types.js';
import type { IRainbirdManualEntry, TRainbirdProtocol } from './rainbird.types.js';

export class RainbirdManualMatcher implements IDiscoveryMatcher<IRainbirdManualEntry> {
  public id = 'rainbird-manual-match';
  public source = 'manual' as const;
  public description = 'Recognize manual Rain Bird LNK WiFi controller setup entries.';

  public async matches(inputArg: IRainbirdManualEntry): Promise<IDiscoveryMatch> {
    const mac = normalizeMac(inputArg.macAddress || inputArg.id);
    const haystack = `${inputArg.name || ''} ${inputArg.model || ''} ${inputArg.manufacturer || ''}`.toLowerCase();
    const matched = Boolean(inputArg.host || inputArg.metadata?.rainbird || inputArg.metadata?.rainBird || haystack.includes('rain bird') || haystack.includes('rainbird'));
    if (!matched) {
      return { matched: false, confidence: 'low', reason: 'Manual entry does not contain Rain Bird setup hints.' };
    }
    const protocol = protocolValue(inputArg.protocol) || 'auto';
    return {
      matched: true,
      confidence: inputArg.host ? 'high' : 'medium',
      reason: 'Manual entry can start Rain Bird setup.',
      normalizedDeviceId: mac || inputArg.serialNumber || inputArg.id,
      candidate: {
        source: 'manual',
        integrationDomain: 'rainbird',
        id: mac || inputArg.serialNumber || inputArg.id,
        host: inputArg.host,
        port: inputArg.port || (protocol === 'http' ? 80 : protocol === 'https' ? 443 : undefined),
        name: inputArg.name,
        manufacturer: inputArg.manufacturer || 'Rain Bird',
        model: inputArg.model,
        serialNumber: inputArg.serialNumber,
        macAddress: mac || undefined,
        metadata: {
          ...inputArg.metadata,
          protocol,
        },
      },
    };
  }
}

export class RainbirdCandidateValidator implements IDiscoveryValidator {
  public id = 'rainbird-candidate-validator';
  public description = 'Validate that a discovery candidate can be configured as a Rain Bird controller.';

  public async validate(candidateArg: IDiscoveryCandidate): Promise<IDiscoveryMatch> {
    const haystack = `${candidateArg.name || ''} ${candidateArg.model || ''} ${candidateArg.manufacturer || ''}`.toLowerCase();
    const matched = candidateArg.integrationDomain === 'rainbird' || haystack.includes('rain bird') || haystack.includes('rainbird') || Boolean(candidateArg.metadata?.rainbird || candidateArg.metadata?.rainBird);
    const mac = normalizeMac(candidateArg.macAddress || candidateArg.id);
    return {
      matched,
      confidence: matched && candidateArg.host ? 'high' : matched ? 'medium' : 'low',
      reason: matched ? 'Candidate has Rain Bird metadata.' : 'Candidate is not Rain Bird.',
      normalizedDeviceId: mac || candidateArg.serialNumber || candidateArg.id,
      candidate: matched ? {
        ...candidateArg,
        integrationDomain: 'rainbird',
        manufacturer: candidateArg.manufacturer || 'Rain Bird',
        id: candidateArg.id || mac || candidateArg.serialNumber,
        macAddress: candidateArg.macAddress || mac || undefined,
      } : undefined,
    };
  }
}

export const createRainbirdDiscoveryDescriptor = (): DiscoveryDescriptor => {
  return new DiscoveryDescriptor({ integrationDomain: 'rainbird', displayName: 'Rain Bird' })
    .addMatcher(new RainbirdManualMatcher())
    .addValidator(new RainbirdCandidateValidator());
};

const normalizeMac = (valueArg: string | undefined): string => {
  const cleaned = (valueArg || '').replace(/[^a-fA-F0-9]/g, '').toLowerCase();
  return cleaned.length === 12 ? cleaned : '';
};

const protocolValue = (valueArg: unknown): TRainbirdProtocol | undefined => valueArg === 'auto' || valueArg === 'http' || valueArg === 'https' ? valueArg : undefined;
