// update-manager.js creates a Docker instance at module level.
// On test machines without Docker, this is fine — Docker methods are only called
// in async methods that we won't invoke in unit tests.

const updateManager = require('../update-manager');

beforeEach(() => {
  // Reset singleton state
  updateManager.history = [];
  updateManager.availableUpdates = new Map();
  updateManager.config = { autoUpdate: {} };
  updateManager.checking = false;
  if (updateManager.checkInterval) {
    clearInterval(updateManager.checkInterval);
    updateManager.checkInterval = null;
  }
});

afterAll(() => {
  updateManager.stop();
});

describe('extractTag', () => {
  test('extracts tag from "nginx:latest"', () => {
    expect(updateManager.extractTag('nginx:latest')).toBe('latest');
  });

  test('returns "latest" when no tag specified', () => {
    expect(updateManager.extractTag('nginx')).toBe('latest');
  });

  test('extracts tag from registry/repo:tag format', () => {
    expect(updateManager.extractTag('docker.io/library/nginx:1.21')).toBe('1.21');
  });

  test('handles tags with dots and hyphens', () => {
    expect(updateManager.extractTag('myapp:v1.2.3-rc1')).toBe('v1.2.3-rc1');
  });
});

describe('parseAuthHeader', () => {
  test('returns null for null header', () => {
    expect(updateManager.parseAuthHeader(null)).toBeNull();
  });

  test('returns null for non-Bearer header', () => {
    expect(updateManager.parseAuthHeader('Basic realm="test"')).toBeNull();
  });

  test('parses Bearer realm URL', () => {
    const header = 'Bearer realm="https://auth.docker.io/token"';
    const result = updateManager.parseAuthHeader(header);
    expect(result).toContain('https://auth.docker.io/token');
  });

  test('includes service parameter', () => {
    const header = 'Bearer realm="https://auth.docker.io/token",service="registry.docker.io"';
    const result = updateManager.parseAuthHeader(header);
    expect(result).toContain('service=registry.docker.io');
  });

  test('includes scope parameter', () => {
    const header = 'Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:library/nginx:pull"';
    const result = updateManager.parseAuthHeader(header);
    expect(result).toContain('scope=');
  });
});

describe('getAvailableUpdates', () => {
  test('returns empty array initially', () => {
    expect(updateManager.getAvailableUpdates()).toEqual([]);
  });

  test('returns array from availableUpdates map', () => {
    updateManager.availableUpdates.set('c1', { containerId: 'c1', imageName: 'nginx' });
    const updates = updateManager.getAvailableUpdates();
    expect(updates).toHaveLength(1);
    expect(updates[0].containerId).toBe('c1');
  });
});

describe('getHistory', () => {
  test('returns entries in reverse order', () => {
    updateManager.addToHistory({ containerId: 'c1', status: 'success' });
    updateManager.addToHistory({ containerId: 'c2', status: 'success' });
    const history = updateManager.getHistory();
    expect(history[0].containerId).toBe('c2');
  });

  test('returns empty array when no history', () => {
    expect(updateManager.getHistory()).toEqual([]);
  });

  test('respects limit parameter', () => {
    for (let i = 0; i < 10; i++) {
      updateManager.addToHistory({ containerId: `c${i}` });
    }
    expect(updateManager.getHistory(3)).toHaveLength(3);
  });
});

describe('addToHistory', () => {
  test('appends entry', () => {
    updateManager.addToHistory({ containerId: 'c1' });
    expect(updateManager.history).toHaveLength(1);
  });

  test('trims to 100 entries', () => {
    for (let i = 0; i < 105; i++) {
      updateManager.addToHistory({ containerId: `c${i}` });
    }
    expect(updateManager.history.length).toBeLessThanOrEqual(100);
  });
});

describe('configureAutoUpdate', () => {
  test('creates autoUpdate config section', () => {
    updateManager.configureAutoUpdate('c1', { enabled: true });
    expect(updateManager.config.autoUpdate['c1']).toBeDefined();
  });

  test('stores container-specific config', () => {
    updateManager.configureAutoUpdate('c1', {
      enabled: true,
      schedule: 'daily',
      securityOnly: true
    });
    expect(updateManager.config.autoUpdate['c1'].schedule).toBe('daily');
    expect(updateManager.config.autoUpdate['c1'].securityOnly).toBe(true);
  });

  test('defaults autoRollback to true', () => {
    updateManager.configureAutoUpdate('c1', { enabled: true });
    expect(updateManager.config.autoUpdate['c1'].autoRollback).toBe(true);
  });

  test('defaults schedule to weekly', () => {
    updateManager.configureAutoUpdate('c1', {});
    expect(updateManager.config.autoUpdate['c1'].schedule).toBe('weekly');
  });
});

describe('scheduleUpdate', () => {
  test('throws for past scheduled time', () => {
    const past = new Date(Date.now() - 60000).toISOString();
    expect(() => updateManager.scheduleUpdate('c1', past)).toThrow('Scheduled time must be in the future');
  });

  test('accepts future scheduled time', () => {
    jest.useFakeTimers();
    const future = new Date(Date.now() + 60000).toISOString();
    expect(() => updateManager.scheduleUpdate('c1', future)).not.toThrow();
    jest.useRealTimers();
  });
});

describe('getChangelog', () => {
  test('returns placeholder response', async () => {
    const result = await updateManager.getChangelog('nginx:latest');
    expect(result.imageName).toBe('nginx:latest');
    expect(result.changelog).toBeDefined();
  });
});

describe('start / stop', () => {
  test('start sets checking flag', () => {
    jest.useFakeTimers();
    updateManager.start();
    expect(updateManager.checking).toBe(true);
    updateManager.stop();
    jest.useRealTimers();
  });

  test('stop clears interval', () => {
    jest.useFakeTimers();
    updateManager.start();
    updateManager.stop();
    expect(updateManager.checking).toBe(false);
    expect(updateManager.checkInterval).toBeNull();
    jest.useRealTimers();
  });

  test('start is idempotent', () => {
    jest.useFakeTimers();
    updateManager.start();
    const first = updateManager.checkInterval;
    updateManager.start();
    expect(updateManager.checkInterval).toBe(first);
    updateManager.stop();
    jest.useRealTimers();
  });
});
