/**
 * Unit Test — Auto-Skip Expired Invoices
 * Menguji logika auto-skip di cronJob.js
 */

// Mock dependencies sebelum require module
jest.mock('../models', () => ({
  invoice: {
    findAll: jest.fn(),
    update: jest.fn(),
  },
  setting: {
    findOne: jest.fn(),
    findAll: jest.fn(),
  }
}));

jest.mock('../libs/cronJob', () => {
  // Require actual module tapi dengan mocked DB
  const actual = jest.requireActual('../libs/cronJob');
  return actual;
});

jest.mock('../services/emailService', () => ({
  sendAutoSkipNotification: jest.fn().mockResolvedValue(undefined),
  testSmtpConnection: jest.fn()
}));

jest.mock('nodejs-log-agent', () => ({
  logger: {
    info: jest.fn(),
    warn: jest.fn(),
    error: jest.fn()
  }
}));

jest.mock('node-cron', () => ({
  schedule: jest.fn(() => ({
    start: jest.fn(),
    stop: jest.fn()
  }))
}));

const db = require('../models');
const { sendAutoSkipNotification } = require('../services/emailService');
const { autoSkipExpiredInvoices } = require('../libs/cronJob');

describe('autoSkipExpiredInvoices()', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  test('✅ SUKSES: Tidak ada invoice yang expired — tidak ada update', async () => {
    // Setup: fitur aktif, threshold 24 jam, tidak ada invoice expired
    db.setting.findOne
      .mockResolvedValueOnce({ value: '24' })   // threshold
      .mockResolvedValueOnce({ value: 'true' }); // enabled

    db.invoice.findAll.mockResolvedValue([]);

    const result = await autoSkipExpiredInvoices();

    expect(result).toEqual([]);
    expect(db.invoice.update).not.toHaveBeenCalled();
    expect(sendAutoSkipNotification).not.toHaveBeenCalled();
  });

  test('✅ SUKSES: Ada invoice expired — harus di-update dan notifikasi dikirim', async () => {
    const mockExpiredInvoices = [
      { inv_id: 'INV-001', inv_name: 'Client A', inv_type: 'created', phoneNumber: '628123456789', createdAt: new Date(Date.now() - 30 * 60 * 60 * 1000) },
      { inv_id: 'INV-002', inv_name: 'Client B', inv_type: 'reminder', phoneNumber: '628987654321', createdAt: new Date(Date.now() - 48 * 60 * 60 * 1000) },
    ];

    db.setting.findOne
      .mockResolvedValueOnce({ value: '24' })
      .mockResolvedValueOnce({ value: 'true' });

    db.invoice.findAll.mockResolvedValue(mockExpiredInvoices);
    db.invoice.update.mockResolvedValue([2]);

    const result = await autoSkipExpiredInvoices();

    expect(result).toHaveLength(2);
    expect(db.invoice.update).toHaveBeenCalledWith(
      expect.objectContaining({
        delivered: true,
        skip_reason: 'auto_expired',
        skipped_by: 'system'
      }),
      expect.objectContaining({
        where: expect.any(Object)
      })
    );
    // Email notifikasi dipanggil secara async (tidak perlu await)
    expect(result[0].inv_id).toBe('INV-001');
    expect(result[1].inv_id).toBe('INV-002');
  });

  test('❌ GAGAL: Fitur auto-skip dinonaktifkan dari settings', async () => {
    db.setting.findOne
      .mockResolvedValueOnce({ value: '24' })
      .mockResolvedValueOnce({ value: 'false' }); // dinonaktifkan

    const result = await autoSkipExpiredInvoices();

    expect(result).toEqual([]);
    expect(db.invoice.findAll).not.toHaveBeenCalled();
    expect(db.invoice.update).not.toHaveBeenCalled();
  });

  test('✅ SUKSES: Threshold custom dari settings digunakan', async () => {
    db.setting.findOne
      .mockResolvedValueOnce({ value: '48' })   // threshold 48 jam
      .mockResolvedValueOnce({ value: 'true' });

    db.invoice.findAll.mockResolvedValue([]);

    await autoSkipExpiredInvoices();

    // Verifikasi bahwa findAll dipanggil (dengan cutoff yang sesuai)
    expect(db.invoice.findAll).toHaveBeenCalledWith(
      expect.objectContaining({
        where: expect.objectContaining({
          delivered: false
        })
      })
    );
  });

  test('✅ SUKSES: DB error pada findAll tidak crash seluruh sistem', async () => {
    db.setting.findOne
      .mockResolvedValueOnce({ value: '24' })
      .mockResolvedValueOnce({ value: 'true' });

    db.invoice.findAll.mockRejectedValue(new Error('DB Connection Error'));

    // Tidak boleh throw error — harus return array kosong
    const result = await autoSkipExpiredInvoices();
    expect(result).toEqual([]);
  });
});
