import { describe, expect, it } from 'vitest'
import { toFeed, type FeedMeta } from './feed.js'
import type { ContentEntry } from './model.js'

const meta: FeedMeta = { title: 'Site', siteUrl: 'https://x.test/', feedUrl: 'https://x.test/feed.xml' }

function entry(over: Partial<ContentEntry>): ContentEntry {
  return {
    id: 'i', slug: 's', type: 'post', title: 'T', body: '<p>b</p>',
    status: 'published', publishedAt: new Date(Date.parse('2026-06-17T00:00:00.000Z')),
    visibility: 'public',
    author: 'u', terms: [],
    createdAt: new Date(0), updatedAt: new Date(0),
    parentId: null, menuOrder: 0, templateKey: null, excerpt: '', featuredMedia: null,
    commentStatus: 'open', pingStatus: 'open', passwordProtected: false, sticky: false,
    format: null, deletedAt: null, lastEditedBy: 'u', typeDefinitionRevision: 1, statusDefinitionRevision: 1,
    ...over,
  }
}

describe('toFeed', () => {
  it('includes only published entries, newest first', () => {
    const out = toFeed(
      [
        entry({ id: 'old', slug: 'old', publishedAt: new Date(Date.parse('2026-01-01T00:00:00Z')) }),
        entry({ id: 'draft', slug: 'draft', status: 'draft', publishedAt: null }),
        entry({ id: 'new', slug: 'new', publishedAt: new Date(Date.parse('2026-06-01T00:00:00Z')) }),
      ],
      'json',
      meta,
    )
    const parsed = JSON.parse(out)
    expect(parsed.items.map((i: { id: string }) => i.id)).toEqual([
      'https://x.test/post/new',
      'https://x.test/post/old',
    ])
  })

  it('escapes XML metacharacters in the RSS output', () => {
    const out = toFeed([entry({ title: 'A & B <c>', slug: 'amp' })], 'rss', meta)
    expect(out).toContain('<title>A &amp; B &lt;c&gt;</title>')
    expect(out).toContain('<?xml version="1.0" encoding="UTF-8"?>')
  })

  it('produces a JSON Feed 1.1 envelope', () => {
    const parsed = JSON.parse(toFeed([entry({})], 'json', meta))
    expect(parsed.version).toBe('https://jsonfeed.org/version/1.1')
    expect(parsed.feed_url).toBe('https://x.test/feed.xml')
  })

  it('emits tag slugs from assigned tag terms', () => {
    const out = toFeed(
      [
        entry({
          terms: [
            { id: '1', taxonomy: 'tag', slug: 'alpha', name: 'Alpha', parentId: null, depth: 0 },
            { id: '2', taxonomy: 'category', slug: 'news', name: 'News', parentId: null, depth: 0 },
          ],
        }),
      ],
      'json',
      meta,
    )
    expect(JSON.parse(out).items[0].tags).toEqual(['alpha'])
  })

  it('omits tags when entry has no tag terms', () => {
    const parsed = JSON.parse(toFeed([entry({ terms: [] })], 'json', meta))
    expect(parsed.items[0].tags).toBeUndefined()
  })
})
