import { beforeEach, describe, expect, it, vi } from 'vitest'
import { Hono } from 'hono'
import type { AppEnv } from '../src/types'

const mockGetInvoicePdfTemplate = vi.fn()
const mockUpdateInvoicePdfTemplate = vi.fn()
const mockCreateDb = vi.fn(() => ({}))

vi.mock('../src/middleware/auth', () => ({
  authMiddleware: async (c: { set: (key: string, value: unknown) => void }, next: () => Promise<void>) => {
    c.set('session', {
      type: 'user',
      sub: 'user-1',
      tid: 'tenant-1',
      role: 'OWNER',
      permissions: ['settings:read', 'settings:write'],
    })
    await next()
  },
}))

vi.mock('../src/middleware/guards', () => ({
  requirePermission: (permission: string) => {
    return async (
      c: {
        get: (key: string) => { permissions?: string[] } | undefined
        json: (body: unknown, status: number) => Response
      },
      next: () => Promise<void>,
    ) => {
      const session = c.get('session')
      if (!session?.permissions?.includes(permission)) {
        return c.json({ error: 'Forbidden' }, 403)
      }
      await next()
    }
  },
}))

vi.mock('@zync/db/queries', async () => {
  const actual = await vi.importActual<Record<string, unknown>>('@zync/db/queries')
  return {
    ...actual,
    createDb: (...args: unknown[]) => mockCreateDb(...args),
    getInvoicePdfTemplate: (...args: unknown[]) => mockGetInvoicePdfTemplate(...args),
    updateInvoicePdfTemplate: (...args: unknown[]) => mockUpdateInvoicePdfTemplate(...args),
  }
})

function buildTemplate() {
  return {
    layout: 'classic' as const,
    showProject: false,
    showSku: false,
    dateFormat: 'dd.MM.yyyy' as const,
    accentHex: null,
  }
}

async function appForRoute() {
  const { pdfTemplateSettingsRoute } = await import('../src/routes/settings/pdf-template')
  const app = new Hono<AppEnv>()
  app.route('/api/settings/invoicing/pdf-template', pdfTemplateSettingsRoute)
  return app
}

describe('invoice pdf template settings route', () => {
  beforeEach(() => {
    vi.resetModules()
    vi.clearAllMocks()
    mockGetInvoicePdfTemplate.mockResolvedValue(buildTemplate())
    mockUpdateInvoicePdfTemplate.mockResolvedValue(buildTemplate())
    vi.stubGlobal(
      'fetch',
      vi.fn().mockResolvedValue(
        new Response(new Uint8Array([0x25, 0x50, 0x44, 0x46]), {
          status: 200,
          headers: { 'Content-Type': 'application/pdf' },
        }),
      ),
    )
  })

  it('returns a PDF preview that merges query overrides over stored settings', async () => {
    const app = await appForRoute()
    const res = await app.request(
      '/api/settings/invoicing/pdf-template/preview?layout=minimal&showProject=true&accentHex=%2300aa00',
    )

    expect(res.status).toBe(200)
    expect(res.headers.get('Content-Type')).toBe('application/pdf')
    expect(res.headers.get('Content-Disposition')).toContain('sample-invoice.pdf')
    expect(mockGetInvoicePdfTemplate).toHaveBeenCalledWith({}, 'tenant-1')
    expect(fetch).toHaveBeenCalledTimes(1)
    const [url, init] = vi.mocked(fetch).mock.calls[0]!
    expect(url).toBe('https://api.html-to-pdf.zync.is')
    expect(String(init?.body)).toContain('Project')
    expect(String(init?.body)).toContain('01.06.2026')
    expect(String(init?.body)).not.toContain('#00aa00')
  }, 30_000)

  it('rejects invalid preview query params', async () => {
    const app = await appForRoute()
    const res = await app.request('/api/settings/invoicing/pdf-template/preview?accentHex=teal')

    expect(res.status).toBe(400)
    expect(fetch).not.toHaveBeenCalled()
  }, 30_000)
})
