import { beforeEach, describe, expect, it, vi } from 'vitest'
import { prisma } from '../lib/prisma'
import { generateFinancialReport, toCsv } from './financialReportService'

vi.mock('../lib/prisma', () => ({
  prisma: {
    reservation: { findMany: vi.fn() },
  },
}))

describe('financialReportService', () => {
  beforeEach(() => vi.clearAllMocks())

  it('generates summary totals and rows from confirmed revenue-bearing reservations only as requested from Prisma', async () => {
    const startDate = new Date('2026-06-01T00:00:00.000Z')
    const endDate = new Date('2026-06-30T23:59:59.999Z')

    vi.mocked(prisma.reservation.findMany).mockResolvedValue([
      {
        id: 'reservation_1',
        contractNumber: 'CNT-1',
        invoiceNumber: null,
        dailyRate: 500,
        totalDays: 3,
        discountAmount: 100,
        insuranceTotal: 60,
        additionalDriverTotal: 40,
        pricingRulesTotal: -25,
        depositAmount: 1000,
        totalAmount: 1475,
        source: 'DIRECT',
        startDate: new Date('2026-06-10T10:00:00.000Z'),
        endDate: new Date('2026-06-13T10:00:00.000Z'),
        vehicle: { year: 2024, make: 'Dacia', model: 'Duster', licensePlate: 'A-123' },
        customer: { firstName: 'Nora', lastName: 'Saidi', email: 'nora@example.com' },
        rentalPayments: [{ status: 'SUCCEEDED', paymentMethod: 'CARD' }],
        insurances: [],
        additionalDrivers: [],
      },
      {
        id: 'reservation_2',
        contractNumber: null,
        invoiceNumber: 'INV-2',
        dailyRate: 300,
        totalDays: 2,
        discountAmount: 0,
        insuranceTotal: 30,
        additionalDriverTotal: 0,
        pricingRulesTotal: 10,
        depositAmount: 500,
        totalAmount: 640,
        source: 'CARPLACE',
        startDate: new Date('2026-06-18T10:00:00.000Z'),
        endDate: new Date('2026-06-20T10:00:00.000Z'),
        vehicle: { year: 2023, make: 'Renault', model: 'Clio', licensePlate: 'B-456' },
        customer: { firstName: 'Omar', lastName: 'Tazi', email: 'omar@example.com' },
        rentalPayments: [],
        insurances: [],
        additionalDrivers: [],
      },
    ] as never)

    const report = await generateFinancialReport('company_1', startDate, endDate)

    expect(prisma.reservation.findMany).toHaveBeenCalledWith({
      where: {
        companyId: 'company_1',
        status: { in: ['CONFIRMED', 'ACTIVE', 'COMPLETED'] },
        startDate: { gte: startDate },
        endDate: { lte: endDate },
      },
      include: expect.objectContaining({
        vehicle: { select: { make: true, model: true, year: true, licensePlate: true } },
        customer: { select: { firstName: true, lastName: true, email: true } },
        rentalPayments: { where: { status: 'SUCCEEDED' } },
      }),
      orderBy: { startDate: 'asc' },
    })

    expect(report.summary).toEqual({
      totalReservations: 2,
      totalRentalRevenue: 2100,
      totalDiscounts: 100,
      totalInsurance: 90,
      totalAdditionalDrivers: 40,
      totalPricingRulesAdj: -15,
      totalDeposits: 1500,
      totalCollected: 2115,
      averageRentalDays: 2.5,
    })
    expect(report.rows).toEqual([
      expect.objectContaining({
        reservationId: 'reservation_1',
        contractNumber: 'CNT-1',
        invoiceNumber: '—',
        customerName: 'Nora Saidi',
        vehicle: '2024 Dacia Duster',
        plate: 'A-123',
        startDate: '2026-06-10',
        endDate: '2026-06-13',
        baseAmount: 1500,
        paymentStatus: 'SUCCEEDED',
        paymentMethod: 'CARD',
      }),
      expect.objectContaining({
        reservationId: 'reservation_2',
        contractNumber: '—',
        invoiceNumber: 'INV-2',
        paymentStatus: 'UNPAID',
        paymentMethod: '—',
      }),
    ])
    expect(report.period).toEqual({ startDate, endDate })
  })

  it('returns zero-safe summary values when no rows match', async () => {
    vi.mocked(prisma.reservation.findMany).mockResolvedValue([] as never)

    const report = await generateFinancialReport('company_1', new Date('2026-06-01'), new Date('2026-06-30'))

    expect(report.summary).toMatchObject({
      totalReservations: 0,
      totalRentalRevenue: 0,
      averageRentalDays: 0,
    })
    expect(report.rows).toEqual([])
  })

  it('serializes CSV rows with headers and quotes comma-containing string values', () => {
    expect(toCsv([
      { customerName: 'Nora, Saidi', totalAmount: 1200, paymentStatus: 'SUCCEEDED' },
      { customerName: 'Omar Tazi', totalAmount: 900, paymentStatus: null },
    ])).toBe('customerName,totalAmount,paymentStatus\n"Nora, Saidi",1200,SUCCEEDED\nOmar Tazi,900,')
  })

  it('returns an empty CSV string for empty rows', () => {
    expect(toCsv([])).toBe('')
  })
})
