/**
 * Tests for js/utils/helpers.js
 */

import { test, describe, assertEquals, assertTrue } from './test-runner.js'
import { escapeHTML, formatPrice, formatRelativeTime, debounce, truncate } from '../js/utils/helpers.js'

describe('escapeHTML', () => {
    test('escapes < and >', () => {
        assertEquals(escapeHTML('<script>'), '&lt;script&gt;')
    })

    test('escapes quotes', () => {
        assertEquals(escapeHTML('"hello"'), '&quot;hello&quot;')
    })

    test('escapes ampersand', () => {
        assertEquals(escapeHTML('a & b'), 'a &amp; b')
    })

    test('escapes single quotes', () => {
        assertEquals(escapeHTML("it's"), "it&#039;s")
    })

    test('handles null', () => {
        assertEquals(escapeHTML(null), '')
    })

    test('handles undefined', () => {
        assertEquals(escapeHTML(undefined), '')
    })

    test('handles numbers by converting to string', () => {
        assertEquals(escapeHTML(123), '123')
    })

    test('handles complex XSS attempt', () => {
        const xss = '<img src="x" onerror="alert(1)">'
        assertTrue(!escapeHTML(xss).includes('<'))
    })
})

describe('formatPrice', () => {
    test('formats EUR correctly', () => {
        assertEquals(formatPrice(99.5, 'EUR'), '€ 99.50')
    })

    test('formats USD correctly', () => {
        assertEquals(formatPrice(99.5, 'USD'), '$ 99.50')
    })

    test('formats CHF correctly', () => {
        assertEquals(formatPrice(99.5, 'CHF'), 'CHF 99.50')
    })

    test('formats XMR with 4 decimals', () => {
        assertEquals(formatPrice(0.5, 'XMR'), '0.5000 ɱ')
    })

    test('handles null price', () => {
        assertEquals(formatPrice(null, 'EUR'), '–')
    })

    test('handles undefined price', () => {
        assertEquals(formatPrice(undefined, 'EUR'), '–')
    })

    test('defaults to EUR', () => {
        assertEquals(formatPrice(10), '€ 10.00')
    })

    test('handles unknown currency', () => {
        assertEquals(formatPrice(10, 'GBP'), 'GBP 10.00')
    })
})

describe('formatRelativeTime', () => {
    test('formats seconds ago', () => {
        const date = new Date(Date.now() - 30000) // 30 seconds ago
        const result = formatRelativeTime(date, 'en')
        assertTrue(result.includes('second'))
    })

    test('formats minutes ago', () => {
        const date = new Date(Date.now() - 5 * 60000) // 5 minutes ago
        const result = formatRelativeTime(date, 'en')
        assertTrue(result.includes('minute'))
    })

    test('formats hours ago', () => {
        const date = new Date(Date.now() - 2 * 3600000) // 2 hours ago
        const result = formatRelativeTime(date, 'en')
        assertTrue(result.includes('hour'))
    })

    test('formats days ago', () => {
        const date = new Date(Date.now() - 3 * 86400000) // 3 days ago
        const result = formatRelativeTime(date, 'en')
        assertTrue(result.includes('day'))
    })

    test('accepts string date', () => {
        const date = new Date(Date.now() - 60000).toISOString()
        const result = formatRelativeTime(date, 'en')
        assertTrue(result.includes('minute'))
    })

    test('respects locale de', () => {
        const date = new Date(Date.now() - 60000)
        const result = formatRelativeTime(date, 'de')
        assertTrue(result.includes('Minute'))
    })
})

describe('truncate', () => {
    test('truncates long strings', () => {
        assertEquals(truncate('Hello World', 6), 'Hello…')
    })

    test('does not truncate short strings', () => {
        assertEquals(truncate('Hi', 10), 'Hi')
    })

    test('handles exact length', () => {
        assertEquals(truncate('Hello', 5), 'Hello')
    })

    test('handles null', () => {
        assertEquals(truncate(null, 10), null)
    })

    test('handles empty string', () => {
        assertEquals(truncate('', 10), '')
    })

    test('uses default maxLength of 100', () => {
        const long = 'a'.repeat(150)
        const result = truncate(long)
        assertEquals(result.length, 100)
        assertTrue(result.endsWith('…'))
    })
})

describe('debounce', () => {
    test('returns a function', () => {
        const fn = debounce(() => {})
        assertEquals(typeof fn, 'function')
    })

    test('delays execution', (done) => {
        let called = false
        const fn = debounce(() => { called = true }, 50)
        
        fn()
        assertEquals(called, false)
    })
})
