/**
 * Smoke tests for dns-propagation.js
 * Verifies DNS propagation checker module loads, exposes the expected
 * interface, and basic methods (verifyRecord, startVerification,
 * getVerificationStatus, getAllVerifications, cleanup) work without throwing.
 */

// The module does `const dns = require('dns').promises;` then `new dns.Resolver()`.
// We mock the dns module so that .promises exposes our Resolver class.
jest.mock('dns', () => {
  class MockResolver {
    setServers() { return this; }
    setTimeout() { return this; }
    resolve4(domain) {
      if (domain === 'propagated.sami') {
        return Promise.resolve(['1.2.3.4']);
      }
      return Promise.resolve(['9.9.9.9']);
    }
  }
  return {
    promises: { Resolver: MockResolver },
    Resolver: MockResolver,
  };
});

const DNSPropagationChecker = require('../src/dns/dns-propagation');

describe('DNSPropagationChecker', () => {
  let checker;

  beforeEach(() => {
    const ctx = {
      log: { error: jest.fn(), info: jest.fn(), warn: jest.fn() },
      notification: { send: jest.fn().mockResolvedValue({ success: true }) },
    };
    checker = new DNSPropagationChecker(ctx);
  });

  test('is an EventEmitter', () => {
    expect(typeof checker.on).toBe('function');
    expect(typeof checker.emit).toBe('function');
  });

  test('starts with an empty verifications map', () => {
    expect(checker.verifications).toBeInstanceOf(Map);
    expect(checker.verifications.size).toBe(0);
  });

  test('verifyRecord returns expected shape and detects propagated domain', async () => {
    const result = await checker.verifyRecord('propagated.sami', '1.2.3.4', {
      timeout: 5000,
      interval: 100,
      resolvers: ['1.1.1.1'],
    });
    expect(result).toHaveProperty('domain', 'propagated.sami');
    expect(result).toHaveProperty('expectedIp', '1.2.3.4');
    expect(result).toHaveProperty('propagated', true);
    expect(Array.isArray(result.results)).toBe(true);
    expect(result.results.length).toBeGreaterThan(0);
    expect(typeof result.totalTime).toBe('number');
    expect(typeof result.checkedAt).toBe('string');
  });

  test('verifyRecord reports not-propagated when IP does not match', async () => {
    const result = await checker.verifyRecord('notpropagated.sami', '5.6.7.8', {
      timeout: 200,
      interval: 50,
      resolvers: ['1.1.1.1'],
    });
    expect(result.propagated).toBe(false);
  });

  test('startVerification returns a job object with running status', () => {
    const job = checker.startVerification('job.sami', '1.1.1.1', {
      timeout: 100,
      interval: 50,
      resolvers: ['1.1.1.1'],
    });
    expect(job).toMatchObject({
      domain: 'job.sami',
      expectedIp: '1.1.1.1',
      status: 'running',
    });
    expect(job.startedAt).toBeDefined();
  });

  test('startVerification returns the same job when called twice for one domain', () => {
    const a = checker.startVerification('dup.sami', '1.1.1.1', { timeout: 5000, interval: 1000 });
    const b = checker.startVerification('dup.sami', '1.1.1.1', { timeout: 5000, interval: 1000 });
    expect(a).toBe(b);
  });

  test('getVerificationStatus returns null for unknown domain', () => {
    expect(checker.getVerificationStatus('nope.sami')).toBeNull();
  });

  test('getAllVerifications returns an array', () => {
    expect(Array.isArray(checker.getAllVerifications())).toBe(true);
  });

  test('cleanup is a no-op on empty verifications', () => {
    expect(() => checker.cleanup()).not.toThrow();
    expect(checker.verifications.size).toBe(0);
  });
});
