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

const requireModuleEnabledMock = vi.fn(() => async (_c: unknown, next: () => Promise<void>) => next())
const requirePermissionMock = vi.fn(() => async (_c: unknown, next: () => Promise<void>) => next())
const getWithholdingReportMock = vi.fn(async () => ({
  year: 2026,
  total_gross: '1000.00',
  total_withheld: '100.00',
  contractors: [{
    contractor_id: 'ctr-1',
    name: 'Dana',
    tax_id: '123',
    gross_paid: '1000.00',
    withholding_rate: '0.1000',
    withheld_amount: '100.00',
    certificate_number: '456/2026',
    certificate_expiry: '2026-12-31',
  }],
}))

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

vi.mock('../src/middleware/guards', () => ({
  requirePermission: (...args: unknown[]) => requirePermissionMock(...args),
}))

vi.mock('../src/middleware/require-module-enabled', () => ({
  requireModuleEnabled: (...args: unknown[]) => requireModuleEnabledMock(...args),
}))

vi.mock('../src/routes/contractors-portal-invite', () => ({
  contractorPortalInviteRoutes: new Hono<AppEnv>(),
}))

vi.mock('../src/lib/contractor-payout-exports', () => ({
  buildWithholdingReportXlsx: vi.fn(async () => new Uint8Array([1, 2, 3])),
  buildForm857Xlsx: vi.fn(async () => new Uint8Array([4, 5, 6])),
  buildPayoutLedgerXlsx: vi.fn(async () => new Uint8Array([7, 8, 9])),
}))

vi.mock('@zync/notifications', () => ({
  sendEmail: vi.fn(async () => ({ id: 'email-1' })),
}))

vi.mock('@zync/db/queries', async () => {
  const { z } = await import('zod')
  return {
    listContractors: vi.fn(),
    getContractor: vi.fn(async () => ({ id: 'ctr-1', email: 'dana@example.com', withholdingCertificateR2Key: null })),
    createContractor: vi.fn(),
    updateContractor: vi.fn(async () => ({ id: 'ctr-1' })),
    deactivateContractor: vi.fn(),
    listAssignments: vi.fn(),
    createAssignment: vi.fn(),
    updateAssignment: vi.fn(),
    deleteAssignment: vi.fn(),
    listContractorTimeEntries: vi.fn(),
    listPayoutBills: vi.fn(),
    getPayoutBillWithLines: vi.fn(async () => ({ bill: { id: 'bill-1', periodStart: '2026-06-01', periodEnd: '2026-06-30', amount: '1000.00', netAmount: '900.00', currency: 'ILS', status: 'DRAFT' }, lines: [] })),
    generatePayoutBillDraft: vi.fn(),
    updatePayoutBill: vi.fn(async () => ({ bill: { id: 'bill-1', periodStart: '2026-06-01', periodEnd: '2026-06-30', amount: '1000.00', netAmount: '900.00', currency: 'ILS' }, lines: [] })),
    voidPayoutBill: vi.fn(),
    getWithholdingReport: (...args: unknown[]) => getWithholdingReportMock(...args),
    listWithholdingCertificates: vi.fn(),
    addWithholdingCertificate: vi.fn(),
    listAllPayouts: vi.fn(async () => ({ items: [], totalDue: '0.00' })),
    assertTenantOwnsProject: vi.fn(async () => true),
    invalidTenantReferenceBody: vi.fn(() => ({ error: 'invalid_reference' })),
    ContractorNotFoundError: class ContractorNotFoundError extends Error {},
    PayoutBillNotFoundError: class PayoutBillNotFoundError extends Error {},
    PayoutBillConflictError: class PayoutBillConflictError extends Error {},
    createContractorSchema: z.object({}),
    updateContractorSchema: z.object({}),
    listContractorsSchema: z.object({}),
    createAssignmentSchema: z.object({ projectId: z.string().default('project-1') }),
    updateAssignmentSchema: z.object({}),
    generateBillSchema: z.object({}),
    updateBillSchema: z.object({ status: z.string().optional(), lines: z.array(z.any()).optional() }),
    voidBillSchema: z.object({ reason: z.string() }),
    listTimeForContractorSchema: z.object({}),
    withholdingReportSchema: z.object({ year: z.coerce.number() }),
    listPayoutsSchema: z.object({}),
  }
})

describe('contractor payout routes', () => {
  it('guards contractor routes behind contractor_payouts module', async () => {
    await import('../src/routes/contractors/router')
    expect(requireModuleEnabledMock).toHaveBeenCalledWith('contractor_payouts')
  })

  it('serves withholding xlsx with workbook content', async () => {
    const { contractorRoutes } = await import('../src/routes/contractors/router')
    const app = new Hono<AppEnv>()
    app.route('/api/contractors', contractorRoutes)

    const res = await app.request('/api/contractors/withholding-report/xlsx?year=2026')
    expect(res.status).toBe(200)
    expect(res.headers.get('content-type')).toContain('spreadsheetml.sheet')
  })

  it('mounts payout ledger xlsx export', async () => {
    const { payoutRoutes } = await import('../src/routes/contractors/payouts')
    const app = new Hono<AppEnv>()
    app.route('/api/payouts', payoutRoutes)

    const res = await app.request('/api/payouts/xlsx')
    expect(res.status).toBe(200)
    expect(res.headers.get('content-disposition')).toContain('contractor-payout-ledger')
  })
})
