import { DiscoveryDescriptor } from '../../core/classes.discoverydescriptor.js';
import type { IDiscoveryCandidate, IDiscoveryMatch, IDiscoveryMatcher, IDiscoveryValidator } from '../../core/types.js';
import type { IHarmanKardonAvrManualEntry, IHarmanKardonAvrSnapshot } from './harman_kardon_avr.types.js';
import { harmanKardonAvrDefaultName, harmanKardonAvrDefaultPort, harmanKardonAvrDomain } from './harman_kardon_avr.types.js';

export class HarmanKardonAvrManualMatcher implements IDiscoveryMatcher<IHarmanKardonAvrManualEntry> {
  public id = 'harman-kardon-avr-manual-match';
  public source = 'manual' as const;
  public description = 'Recognize manual Harman Kardon/JBL AVR setup entries.';

  public async matches(inputArg: IHarmanKardonAvrManualEntry): Promise<IDiscoveryMatch> {
    const metadata = inputArg.metadata || {};
    const snapshot = inputArg.snapshot || this.snapshotMetadata(metadata);
    const matched = Boolean(
      inputArg.host
      || snapshot
      || inputArg.commandExecutor
      || inputArg.client
      || metadata.harmanKardonAvr
      || metadata.harman_kardon_avr
      || this.brandHint(inputArg.manufacturer)
      || this.brandHint(inputArg.model)
      || this.brandHint(inputArg.name)
    );

    if (!matched) {
      return { matched: false, confidence: 'low', reason: 'Manual entry does not contain Harman Kardon AVR setup hints.' };
    }

    const id = inputArg.id || snapshot?.deviceInfo.serialNumber || inputArg.serialNumber || inputArg.host;
    return {
      matched: true,
      confidence: inputArg.host || snapshot ? 'high' : 'medium',
      reason: 'Manual entry can start Harman Kardon AVR setup.',
      normalizedDeviceId: id,
      candidate: {
        source: 'manual',
        integrationDomain: harmanKardonAvrDomain,
        id,
        host: inputArg.host || snapshot?.deviceInfo.host,
        port: inputArg.port || snapshot?.deviceInfo.port || harmanKardonAvrDefaultPort,
        name: snapshot?.deviceInfo.name || inputArg.name || harmanKardonAvrDefaultName,
        manufacturer: inputArg.manufacturer || snapshot?.deviceInfo.manufacturer || 'Harman Kardon',
        model: inputArg.model || snapshot?.deviceInfo.model,
        serialNumber: inputArg.serialNumber || snapshot?.deviceInfo.serialNumber,
        metadata: {
          ...metadata,
          snapshot,
          zone: inputArg.zone || metadata.zone || snapshot?.deviceInfo.zone,
          sources: inputArg.sources || metadata.sources || snapshot?.state.sourceList,
          state: inputArg.state || metadata.state,
          client: inputArg.client || metadata.client,
          commandExecutor: inputArg.commandExecutor || metadata.commandExecutor,
        },
      },
    };
  }

  private 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;
  }

  private brandHint(valueArg: string | undefined): boolean {
    if (!valueArg) {
      return false;
    }
    const normalized = valueArg.toLowerCase();
    return normalized.includes('harman') || normalized.includes('kardon') || normalized.includes('jbl') || normalized.includes('avr');
  }
}

export class HarmanKardonAvrCandidateValidator implements IDiscoveryValidator {
  public id = 'harman-kardon-avr-candidate-validator';
  public description = 'Validate Harman Kardon/JBL AVR candidate metadata.';

  public async validate(candidateArg: IDiscoveryCandidate): Promise<IDiscoveryMatch> {
    const metadata = candidateArg.metadata || {};
    const snapshot = metadata.snapshot && typeof metadata.snapshot === 'object' && 'deviceInfo' in metadata.snapshot
      ? metadata.snapshot as IHarmanKardonAvrSnapshot
      : undefined;
    const matched = candidateArg.integrationDomain === harmanKardonAvrDomain
      || Boolean(candidateArg.host)
      || Boolean(snapshot)
      || Boolean(metadata.commandExecutor)
      || Boolean(metadata.client)
      || this.brandHint(candidateArg.manufacturer)
      || this.brandHint(candidateArg.model)
      || this.brandHint(candidateArg.name);

    return {
      matched,
      confidence: matched && (candidateArg.host || snapshot) ? 'high' : matched ? 'medium' : 'low',
      reason: matched ? 'Candidate has usable Harman Kardon AVR setup data.' : 'Candidate is not a Harman Kardon AVR.',
      candidate: matched ? candidateArg : undefined,
      normalizedDeviceId: candidateArg.id || candidateArg.serialNumber || snapshot?.deviceInfo.serialNumber || candidateArg.host,
    };
  }

  private brandHint(valueArg: string | undefined): boolean {
    if (!valueArg) {
      return false;
    }
    const normalized = valueArg.toLowerCase();
    return normalized.includes('harman') || normalized.includes('kardon') || normalized.includes('jbl') || normalized.includes('avr');
  }
}

export const createHarmanKardonAvrDiscoveryDescriptor = (): DiscoveryDescriptor => {
  return new DiscoveryDescriptor({ integrationDomain: harmanKardonAvrDomain, displayName: 'Harman Kardon AVR' })
    .addMatcher(new HarmanKardonAvrManualMatcher())
    .addValidator(new HarmanKardonAvrCandidateValidator());
};
