import { describe, expect, it } from 'vitest'
import { renderStatementPdf } from '../src/lib/statement-pdf'
import type { CustomerStatement } from '@zync/types'

const statement: CustomerStatement = {
  customerId: 'customer-1',
  customerName: 'אקמה בע״מ',
  from: '2026-01-01',
  to: '2026-01-31',
  groups: [{
    currency: 'USD',
    openingBalance: 10,
    closingBalance: 25,
    rows: [{
      date: '2026-01-15',
      kind: 'invoice',
      documentType: 'Invoice',
      documentNumber: 'INV-1',
      reference: null,
      sourceId: 'invoice-1',
      debit: 15,
      credit: 0,
      runningBalance: 25,
    }],
  }],
  aging: { d0_30: 25, d31_60: 0, d61_90: 0, d90plus: 0 },
}

describe('renderStatementPdf', () => {

  const validPdf = new TextEncoder().encode(
    '%PDF-1.7\n1 0 obj\n<< /Type /Catalog >>\nendobj\nxref\n0 2\n0000000000 65535 f \n0000000009 00000 n \ntrailer\n<< /Root 1 0 R /Size 2 >>\nstartxref\n42\n%%EOF\n',
  )

  it('preserves the Hebrew RTL statement when converting it to PDF', async () => {
    let request: RequestInit | undefined
    const pdfFetch = async (_input: RequestInfo | URL, init?: RequestInit) => {
      request = init
      return new Response(validPdf, {
        headers: { 'Content-Type': 'application/pdf' },
      })
    }

    const bytes = await renderStatementPdf(statement, pdfFetch)
    const html = String(request?.body ?? '')

    expect(bytes).toEqual(validPdf)
    expect(html).toContain('<html dir="rtl" lang="he">')
    expect(html).toContain('אקמה בע״מ')
  })

  it('rejects provider non-2xx responses without exposing the provider body', async () => {
    const pdfFetch = async () => new Response('provider secret', { status: 503 })

    await expect(renderStatementPdf(statement, pdfFetch)).rejects.toMatchObject({
      code: 'STATEMENT_PDF_UPSTREAM_ERROR',
      upstreamStatus: 503,
    })
    await expect(renderStatementPdf(statement, pdfFetch)).rejects.not.toThrow('provider secret')
  })

  it('rejects a non-PDF content type', async () => {
    const pdfFetch = async () => new Response(validPdf, {
      headers: { 'Content-Type': 'text/html; charset=utf-8' },
    })

    await expect(renderStatementPdf(statement, pdfFetch)).rejects.toMatchObject({
      code: 'STATEMENT_PDF_INVALID_CONTENT_TYPE',
    })
  })

  it('rejects HTML that masquerades as a PDF', async () => {
    const pdfFetch = async () => new Response('<!doctype html><html>provider error</html>', {
      headers: { 'Content-Type': 'application/pdf' },
    })

    await expect(renderStatementPdf(statement, pdfFetch)).rejects.toMatchObject({
      code: 'STATEMENT_PDF_INVALID_BYTES',
    })
  })

  it('rejects JSON that masquerades as a PDF', async () => {
    const pdfFetch = async () => new Response('{"error":"provider failure"}', {
      headers: { 'Content-Type': 'application/pdf' },
    })

    await expect(renderStatementPdf(statement, pdfFetch)).rejects.toMatchObject({
      code: 'STATEMENT_PDF_INVALID_BYTES',
    })
  })

  it('rejects bytes without a PDF header', async () => {
    const pdfFetch = async () => new Response(
      new TextEncoder().encode('not-a-pdf\nstartxref\n42\n%%EOF\n'),
      { headers: { 'Content-Type': 'application/pdf' } },
    )

    await expect(renderStatementPdf(statement, pdfFetch)).rejects.toMatchObject({
      code: 'STATEMENT_PDF_INVALID_BYTES',
    })
  })

  it('rejects empty provider output', async () => {
    const pdfFetch = async () => new Response(new Uint8Array(), {
      headers: { 'Content-Type': 'application/pdf' },
    })

    await expect(renderStatementPdf(statement, pdfFetch)).rejects.toMatchObject({
      code: 'STATEMENT_PDF_INVALID_BYTES',
    })
  })

  it('rejects a truncated PDF without a terminal EOF marker', async () => {
    const pdfFetch = async () => new Response(validPdf.slice(0, -7), {
      headers: { 'Content-Type': 'application/pdf' },
    })

    await expect(renderStatementPdf(statement, pdfFetch)).rejects.toMatchObject({
      code: 'STATEMENT_PDF_INVALID_BYTES',
    })
  })
})
