// e:\dev\nodejs\invoiceGenerate\controllers\generatePDFController.test.js

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

jest.mock('../libs/pdfGenerate', () => ({
  generatePDF: jest.fn(),
}));

jest.mock("../models", () => ({
  invoice: {
    update: jest.fn(),
    findOne: jest.fn(),
  },
  // Anda bisa menambahkan mock untuk model lain jika diperlukan
}));

const { generatePDFController, generateBYID } = require('../controllers/generatePDFController');
const { generatePDF } = require('../libs/pdfGenerate');
const db = require('../models');
const { logger } = require('nodejs-log-agent');

// Helper untuk membuat mock object response Express
const mockResponse = () => {
  const res = {};
  res.status = jest.fn().mockReturnValue(res);
  res.json = jest.fn().mockReturnValue(res);
  return res;
};

// Data valid untuk testing
const validInvoiceData = {
    client_name: "John Doe",
    client_phone: "0895355389559",
    client_address: "123 Main St",
    inv_id: "INV-2024-001",
    inv_status: "Paid",
    inv_date: "Senin, 20 Mei 2024",
    inv_duedate: "Rabu, 29 Mei 2024",
    sub_total: "100000",
    total: "110000",
    ppn: "10000",
    credit: "0",
    balance: "110000",
    company: {
      name: "PT. Semut Data Indonesia",
      address: "Ruko Amparan Jati Blok A No.06, Margajaya, Bogor Barat",
      phone: "0251 8471670",
      whatsapp: "+62 811 1185 911"
    },
    items: [{ id: 1, description: "Hosting", amount: "100000" }],
    transaction: [{ id: 1, gateway: "Bank Transfer", date: "Senin, 20 Mei 2024", description: "Payment", amount: "110000" }]
};


describe('generatePDFController', () => {
  
  beforeEach(() => {
    // Reset semua mock sebelum setiap test
    jest.clearAllMocks();
  });

  it('should generate PDF successfully with valid data', async () => {
    const req = { body: validInvoiceData };
    const res = mockResponse();

    // Mock hasil sukses dari generatePDF dan update DB
    generatePDF.mockResolvedValue({ status: true, pdfPath: '/path/to/invoice.pdf' });
    db.invoice.update.mockResolvedValue([1]); // 1 row updated

    await generatePDFController(req, res);

    expect(logger.info).toHaveBeenCalledWith(expect.stringContaining(`Start generating PDF for invoice ${validInvoiceData.inv_id}`));
    expect(generatePDF).toHaveBeenCalledWith(validInvoiceData);
    expect(db.invoice.update).toHaveBeenCalledWith(
      { pdfCreated: true, pdfName: '/path/to/invoice.pdf' },
      { where: { inv_id: validInvoiceData.inv_id } }
    );
    expect(res.json).toHaveBeenCalledWith({
      status: true,
      message: 'PDF generated successfully',
      pdfPath: '/path/to/invoice.pdf'
    });
  });

  it('should return 400 if input data is invalid', async () => {
    const invalidData = { ...validInvoiceData, client_name: undefined }; // client_name is required
    const req = { body: invalidData };
    const res = mockResponse();

    await generatePDFController(req, res);

    expect(res.status).toHaveBeenCalledWith(400);
    expect(res.json).toHaveBeenCalledWith({
      status: false,
      message: 'Invalid input',
      error: expect.any(Array)
    });
    expect(logger.warn).toHaveBeenCalled();
  });

  it('should return 500 if PDF generation fails', async () => {
    const req = { body: validInvoiceData };
    const res = mockResponse();

    // Mock hasil gagal dari generatePDF
    generatePDF.mockResolvedValue({ status: false, message: 'Puppeteer error' });

    await generatePDFController(req, res);

    expect(res.status).toHaveBeenCalledWith(500);
    expect(res.json).toHaveBeenCalledWith({
      status: false,
      message: 'Failed to generate PDF',
      error: { status: false, message: 'Puppeteer error' }
    });
    expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('Failed to generate PDF'));
  });

  it('should return 500 on unexpected internal error', async () => {
    const req = { body: validInvoiceData };
    const res = mockResponse();
    const errorMessage = 'Unexpected DB error';

    // Mock generatePDF untuk melempar error
    generatePDF.mockRejectedValue(new Error(errorMessage));

    await generatePDFController(req, res);

    expect(res.status).toHaveBeenCalledWith(500);
    expect(res.json).toHaveBeenCalledWith({
      status: false,
      message: 'Internal server error',
      error: errorMessage
    });
    expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('Unexpected error'), expect.any(Object));
  });
});


describe('generateBYID', () => {

  beforeEach(() => {
    jest.clearAllMocks();
  });

  it('should generate PDF successfully for a given invoice ID', async () => {
    const inv_id = 'INV-001';
    const req = { params: { inv_id } };
    const res = mockResponse();

    const mockDbData = {
        inv_id,
        inv_name: 'Test Client',
        // ... data lain dari model invoice
        invoiceDetails: { client_name: 'Test Client Details' /* ... */ },
        invoiceitem: [{ description: 'Item 1' /* ... */ }],
        invoiceTrans: [{ gateway: 'banktransfer' /* ... */ }]
    };

    db.invoice.findOne.mockResolvedValue(mockDbData);
    generatePDF.mockResolvedValue({ status: true, pdfPath: '/path/to/generated.pdf' });
    db.invoice.update.mockResolvedValue([1]);

    await generateBYID(req, res);

    expect(db.invoice.findOne).toHaveBeenCalledWith(expect.objectContaining({ where: { inv_id } }));
    expect(generatePDF).toHaveBeenCalled();
    expect(res.json).toHaveBeenCalledWith({
      status: true,
      message: 'PDF generated successfully',
      pdfPath: '/path/to/generated.pdf'
    });
  });

  it('should return 404 if invoice not found', async () => {
    const inv_id = 'INV-NOT-FOUND';
    const req = { params: { inv_id } };
    const res = mockResponse();

    db.invoice.findOne.mockResolvedValue(null);

    await generateBYID(req, res);

    expect(res.status).toHaveBeenCalledWith(404);
    expect(res.json).toHaveBeenCalledWith({
      status: false,
      message: 'Invoice not found'
    });
  });

  it('should return 500 if PDF generation fails', async () => {
    const inv_id = 'INV-001';
    const req = { params: { inv_id } };
    const res = mockResponse();

    const mockDbData = { inv_id, inv_name: 'Test Client' /* ... */ };
    db.invoice.findOne.mockResolvedValue(mockDbData);
    
    // Mock kegagalan
    const failureResponse = { status: false, message: 'Internal generator error' };
    generatePDF.mockResolvedValue(failureResponse);

    await generateBYID(req, res);

    expect(res.status).toHaveBeenCalledWith(500);
    expect(res.json).toHaveBeenCalledWith({
      status: false,
      message: 'Failed to generate PDF',
      error: failureResponse
    });
  });
});
