import { describe, expect, it, vi } from 'vitest'
import {
  coerceNotificationLocale,
  formatLocalizedCurrency,
  localizeBillingPeriod,
  localizeInvoiceStatus,
  localizePlanName,
  renderLocalizedEmailHtml,
  renderNotificationText,
  resolveNotificationLocale,
  resolveNotificationTemplate,
} from './notificationLocalizationService'

function dbStub(overrides: Record<string, any> = {}) {
  return {
    employee: { findUnique: vi.fn().mockResolvedValue(null) },
    renter: { findUnique: vi.fn().mockResolvedValue(null) },
    brandSettings: { findUnique: vi.fn().mockResolvedValue(null) },
    billingAccount: { findUnique: vi.fn().mockResolvedValue(null), findFirst: vi.fn().mockResolvedValue(null) },
    notificationTemplate: { findFirst: vi.fn().mockResolvedValue(null) },
    ...overrides,
  }
}

describe('notificationLocalizationService formatting and fallback boundaries', () => {
  it('coerces unsupported or blank locales to English', () => {
    expect(coerceNotificationLocale('fr')).toBe('fr')
    expect(coerceNotificationLocale('es')).toBe('en')
    expect(coerceNotificationLocale(null)).toBe('en')
  })

  it('formats template values across currency, dates and status objects', () => {
    const rendered = renderNotificationText(
      'Total {{amount}}, due {{dueDate}}, status {{invoiceStatus}}, plan {{plan}}',
      {
        amount: { type: 'currency', amountMinor: 123450, currency: 'MAD' },
        dueDate: { type: 'date', value: '2026-06-10T00:00:00.000Z', options: { month: 'short', day: 'numeric' } },
        invoiceStatus: { type: 'invoice_status', status: 'partially_paid' },
        plan: true,
      },
      ['amount', 'dueDate', 'invoiceStatus'],
      'en',
    )

    expect(rendered).toContain('MAD')
    expect(rendered).toContain('Jun')
    expect(rendered).toContain('Partially paid')
    expect(rendered).toContain('true')
  })

  it('throws before rendering when required variables are missing', () => {
    expect(() => renderNotificationText('Hello {{firstName}}', {}, ['firstName'], 'en')).toThrow(
      'Missing notification template variable: firstName',
    )
  })

  it('escapes localized email body text while preserving paragraphs and line breaks', () => {
    const html = renderLocalizedEmailHtml('Hello <Admin> & team\nLine 2\n\nSecond paragraph', 'en')

    expect(html).toContain('&lt;Admin&gt; &amp; team')
    expect(html).toContain('Line 2')
    expect(html).toContain('<br />')
    expect(html).toContain('text-align:left')
  })

  it('uses explicit locale without querying user, workspace or billing preferences', async () => {
    const db = dbStub()

    await expect(resolveNotificationLocale({ locale: 'ar', companyId: 'company_1', employeeId: 'employee_1' }, db as any)).resolves.toBe('ar')

    expect(db.employee.findUnique).not.toHaveBeenCalled()
    expect(db.brandSettings.findUnique).not.toHaveBeenCalled()
    expect(db.billingAccount.findFirst).not.toHaveBeenCalled()
  })

  it('resolves renter preference before workspace and billing defaults', async () => {
    const db = dbStub({
      renter: { findUnique: vi.fn().mockResolvedValue({ preferredLocale: 'fr' }) },
      brandSettings: { findUnique: vi.fn().mockResolvedValue({ defaultLocale: 'ar' }) },
      billingAccount: { findUnique: vi.fn().mockResolvedValue(null), findFirst: vi.fn().mockResolvedValue({ preferredLanguage: 'en' }) },
    })

    await expect(resolveNotificationLocale({ companyId: 'company_1', renterId: 'renter_1' }, db as any)).resolves.toBe('fr')
  })

  it('throws a clear error when neither requested nor fallback templates exist', async () => {
    const db = dbStub()

    await expect(resolveNotificationTemplate({
      templateKey: 'missing.template',
      channel: 'EMAIL',
      locale: 'fr',
    }, db as any)).rejects.toThrow('Missing notification template for missing.template/EMAIL in fr and en')
  })

  it('keeps unknown labels unchanged instead of fabricating translations', () => {
    expect(localizeInvoiceStatus('custom_status', 'fr')).toBe('custom_status')
    expect(localizeBillingPeriod('quarterly', 'ar')).toBe('quarterly')
    expect(localizePlanName('enterprise', 'en')).toBe('enterprise')
    expect(formatLocalizedCurrency(5000, 'MAD', 'fr')).toContain('MAD')
  })
})
