import { describe, expect, it, vi } from 'vitest'
import {
  createCreditNoteDraft,
  createCreditNoteDraftSchema,
  sendInvoice,
} from '../../src/queries/invoices'

function makeCreditNoteDraftDb(parent: { id: string; tenantId: string; source: string; status: string }) {
  const tx = {
    select: vi.fn(() => ({
      from: vi.fn(() => ({
        where: vi.fn(() => ({
          limit: vi.fn(() => ({
            for: vi.fn(async () => [
              {
                ...parent,
                customerId: 'cust-1',
                projectId: null,
                currency: 'ILS',
                vatRate: '18',
                subtotal: '100.00',
                vatAmount: '18.00',
                total: '118.00',
                amountPaid: '0',
                notes: null,
                invoiceNumber: 'INV-1',
                proformaNumber: null,
                issueDate: '2026-06-01',
                taxIssueDate: '2026-06-01',
                sentAt: null,
                approvedAt: null,
                approvedBy: null,
                approvalNote: null,
                rejectionReason: null,
                rejectionNotifyCustomer: false,
                taxIssuedAt: null,
                paidAt: null,
                externalId: null,
                externalProvider: null,
                voidReason: null,
                voidedAt: null,
                voidedBy: null,
                parentInvoiceId: null,
                htmlSnapshotUrl: null,
                createdBy: 'user-1',
                createdAt: new Date('2026-06-01T00:00:00.000Z'),
                updatedAt: new Date('2026-06-01T00:00:00.000Z'),
              },
            ]),
          })),
        })),
      })),
    })),
  }

  return {
    db: {
      transaction: async <T>(fn: (innerTx: typeof tx) => Promise<T>) => fn(tx),
    },
  }
}

describe('createCreditNoteDraftSchema', () => {
  it('accepts partial credit lines with a negative price and positive quantity', () => {
    const parsed = createCreditNoteDraftSchema.safeParse({
      mode: 'partial',
      reason: 'Customer cancellation',
      lines: [
        {
          description: 'Partial refund',
          quantity: 1,
          unitPrice: -50,
        },
      ],
    })

    expect(parsed.success).toBe(true)
  })

  it('rejects partial credit lines whose total is not negative', () => {
    const parsed = createCreditNoteDraftSchema.safeParse({
      mode: 'partial',
      reason: 'Bad line',
      lines: [
        {
          description: 'Broken sign combination',
          quantity: -1,
          unitPrice: -50,
        },
      ],
    })

    expect(parsed.success).toBe(false)
  })
})

describe('createCreditNoteDraft', () => {
  it('rejects PARTIALLY_PAID parent invoices per the spec creation flow', async () => {
    const { db } = makeCreditNoteDraftDb({
      id: 'inv-1',
      tenantId: 'tenant-1',
      source: 'manual',
      status: 'PARTIALLY_PAID',
    })

    await expect(
      createCreditNoteDraft(db as never, 'tenant-1', 'inv-1', 'user-1', {
        mode: 'full',
        reason: 'Partial payments are not creditable through this flow',
      }),
    ).rejects.toThrow('Parent invoice must be in a creditable status')
  })
})

describe('sendInvoice', () => {
  it('rejects credit notes from entering the SENT state', async () => {
    const tx = {
      select: vi.fn(() => ({
        from: vi.fn(() => ({
          where: vi.fn(() => ({
            limit: vi.fn(() => ({
              for: vi.fn(async () => [
                {
                  id: 'cn-1',
                  tenantId: 'tenant-1',
                  source: 'credit_note',
                  status: 'DRAFT',
                },
              ]),
            })),
          })),
        })),
      })),
    }

    const db = {
      transaction: async <T>(fn: (innerTx: typeof tx) => Promise<T>) => fn(tx),
    }

    await expect(
      sendInvoice(db as never, 'tenant-1', 'cn-1', 'user-1', 'IL', '2026-07-03'),
    ).rejects.toThrow('Cannot send a credit note')
  })
})
