import { describe, it, expect, beforeEach } from 'vitest'
import { createSampleItems, createSampleProject, createSampleTemplate } from './testHelpers.js'

// Import generator by loading it as text and evaluating
const fs = await import('fs/promises')
const generatorCode = await fs.readFile('./generator.js', 'utf-8')

describe('Timeline Generator', () => {
  let timelineGenerator

  beforeEach(() => {
    // Reset global window object
    global.window = global

    // Execute generator code
    eval(generatorCode)
    timelineGenerator = global.window.timelineGenerator
  })

  describe('escapeXml', () => {
    it('should escape XML special characters', () => {
      const input = '<test & "quotes" & \'apostrophes\'>'
      const expected = '&lt;test &amp; &quot;quotes&quot; &amp; &#39;apostrophes&#39;&gt;'
      expect(timelineGenerator.escapeXml(input)).toBe(expected)
    })

    it('should handle empty and null values', () => {
      expect(timelineGenerator.escapeXml('')).toBe('')
      expect(timelineGenerator.escapeXml(null)).toBe('null')
      expect(timelineGenerator.escapeXml(undefined)).toBe('undefined')
    })

    it('should convert non-strings to strings', () => {
      expect(timelineGenerator.escapeXml(123)).toBe('123')
      expect(timelineGenerator.escapeXml(true)).toBe('true')
    })
  })

  describe('generate', () => {
    let items, config

    beforeEach(() => {
      items = createSampleItems()
      config = createSampleProject()
    })

    it('should generate SVG with template placeholders', () => {
      const template = createSampleTemplate()
      const result = timelineGenerator.generate(items, config, template)

      expect(result).toContain('<svg xmlns="http://www.w3.org/2000/svg">')
      expect(result).toContain('<rect width="100%" height="100%" fill="#FFFFFF"/>')
      expect(result).not.toContain('{{MONTHS}}')
      expect(result).not.toContain('{{LANES}}')
    })

    it('should generate fallback SVG when no template provided', () => {
      const result = timelineGenerator.generate(items, config, null)

      expect(result).toContain('<svg xmlns="http://www.w3.org/2000/svg"')
      expect(result).toContain('width=')
      expect(result).toContain('height=')
      expect(result).toContain('<rect width="100%" height="100%" fill="#FFFFFF"')
    })

    it('should create month labels and grid lines', () => {
      const result = timelineGenerator.generate(items, config, null)

      expect(result).toContain('<line')
      expect(result).toContain('stroke="#E3E8EF"')
      expect(result).toContain('<text')
      expect(result).toContain('fill="#5C6B7A"')
    })

    it('should create lane backgrounds and labels', () => {
      const result = timelineGenerator.generate(items, config, null)

      expect(result).toContain('Development')
      expect(result).toContain('Testing')
      expect(result).toContain('<rect')
      expect(result).toContain('fill="#FFFFFF"')
    })

    it('should position items correctly in lanes', () => {
      const result = timelineGenerator.generate(items, config, null)

      expect(result).toContain('<circle')
      expect(result).toContain('fill="#0A4D8C"')
      expect(result).toContain('T-1')
      expect(result).toContain('First Task')
    })

    it('should sort items by due date within lanes', () => {
      // Add items with same lane but different dates
      const unsortedItems = [
        { id: 'T-3', title: 'Third', lane: 'Dev', due: new Date('2025-03-01') },
        { id: 'T-1', title: 'First', lane: 'Dev', due: new Date('2025-01-01') },
        { id: 'T-2', title: 'Second', lane: 'Dev', due: new Date('2025-02-01') }
      ]

      const result = timelineGenerator.generate(unsortedItems, config, null)
      const firstIndex = result.indexOf('First')
      const secondIndex = result.indexOf('Second')
      const thirdIndex = result.indexOf('Third')

      expect(firstIndex).toBeLessThan(secondIndex)
      expect(secondIndex).toBeLessThan(thirdIndex)
    })

    it('should handle items without lanes', () => {
      const itemsNoLane = [
        { id: 'T-1', title: 'No Lane Task', lane: null, due: new Date('2025-01-01') }
      ]

      const result = timelineGenerator.generate(itemsNoLane, config, null)
      expect(result).toContain('Ohne Epic')
    })

    it('should respect timelineMonths setting', () => {
      const shortConfig = { ...config, settings: { timelineMonths: 6 } }
      const result = timelineGenerator.generate(items, shortConfig, null)

      // Should create 6 months worth of grid lines
      const lineCount = (result.match(/<line/g) || []).length
      expect(lineCount).toBeGreaterThan(0)
    })

    it('should escape special characters in item text', () => {
      const itemsWithSpecialChars = [{
        id: 'T&1',
        title: 'Task with <special> & "characters"',
        lane: 'Development',
        due: new Date('2025-01-01')
      }]

      const result = timelineGenerator.generate(itemsWithSpecialChars, config, null)

      expect(result).toContain('T&amp;1')
      expect(result).toContain('&lt;special&gt; &amp; &quot;characters&quot;')
    })

    it('should determine start date from earliest item', () => {
      const itemsWithEarlyDate = [
        { id: 'T-1', title: 'Early', lane: 'Dev', due: new Date('2024-06-15') },
        { id: 'T-2', title: 'Late', lane: 'Dev', due: new Date('2025-12-01') }
      ]

      const result = timelineGenerator.generate(itemsWithEarlyDate, config, null)

      // Should start from June 2024 (first day of month)
      expect(result).toContain('Jun 24')
    })

    it('should clamp item positions to timeline bounds', () => {
      const itemsOutOfRange = [
        { id: 'T-1', title: 'In Range', lane: 'Dev', due: new Date('2025-01-01') },
        { id: 'T-2', title: 'Way Future', lane: 'Dev', due: new Date('2030-01-01') }
      ]

      // Should not throw and should generate valid SVG
      const result = timelineGenerator.generate(itemsOutOfRange, config, null)
      expect(result).toContain('<svg')
      expect(result).toContain('T-1')
      expect(result).toContain('T-2')
    })
  })
})