import { describe, expect, it } from 'vitest'
import {
  ContentDefinitionError,
  defineContentType,
  normalizeContentTypeDefinition,
  type ContentTypeCapabilities,
  type ContentTypeDefinition,
  type ContentTypeLabels,
} from './registry.js'

function labels(name = 'Article'): ContentTypeLabels {
  return {
    name: `${name}s`, singularName: name, menuName: `${name}s`, nameAdminBar: name,
    addNew: 'Add New', addNewItem: `Add New ${name}`, editItem: `Edit ${name}`, newItem: `New ${name}`,
    viewItem: `View ${name}`, viewItems: `View ${name}s`, searchItems: `Search ${name}s`, notFound: 'Not found',
    notFoundInTrash: 'Not found in trash', parentItemColon: `Parent ${name}:`, allItems: `All ${name}s`,
    archives: `${name} Archives`, attributes: `${name} Attributes`, insertIntoItem: `Insert into ${name}`,
    uploadedToThisItem: `Uploaded to ${name}`, featuredImage: 'Featured image', setFeaturedImage: 'Set featured image',
    removeFeaturedImage: 'Remove featured image', useFeaturedImage: 'Use featured image', filterItemsList: 'Filter list',
    filterByDate: 'Filter by date', itemsListNavigation: 'List navigation', itemsList: 'Items list',
    itemPublished: 'Published', itemPublishedPrivately: 'Published privately', itemRevertedToDraft: 'Reverted to draft',
    itemScheduled: 'Scheduled', itemUpdated: 'Updated', itemLink: 'Item link', itemLinkDescription: 'Item link description',
  }
}

function capabilities(): ContentTypeCapabilities {
  return {
    manageType: 'manage_type', migrateAll: 'migrate_all', manageTerms: 'manage_terms', create: 'create', read: 'read',
    readPrivate: 'read_private', readProtected: 'read_protected', editOwn: 'edit_own', editOthers: 'edit_others',
    editPrivate: 'edit_private', editPublished: 'edit_published', publish: 'publish', deleteOwn: 'delete_own',
    deleteOthers: 'delete_others', deletePrivate: 'delete_private', deletePublished: 'delete_published',
  }
}

export function contentType(overrides: Partial<ContentTypeDefinition> = {}): ContentTypeDefinition {
  return {
    key: 'article', labels: labels(), public: true, hierarchical: false, excludeFromSearch: false,
    publiclyQueryable: true, showUi: true, showInMenu: true, showInNavMenus: true, showInAdminBar: true,
    capabilities: capabilities(), supports: ['title', 'editor', 'revisions'], taxonomies: [], hasArchive: true,
    rewrite: { slug: 'articles' }, queryVariable: 'article', canExport: true, deleteWithAuthor: false,
    rest: { base: 'articles', namespace: 'content/v1', revisions: true, autosaves: true },
    defaultTemplateKey: 'article-default', active: true, ...overrides,
  }
}

describe('content type registry normalization', () => {
  it('produces immutable deterministic code definitions', () => {
    const code = defineContentType(contentType({ supports: ['revisions', 'editor', 'title', 'editor'], taxonomies: ['tag', 'category', 'tag'] }))
    expect(code.origin).toBe('code')
    expect(code.supports).toEqual(['editor', 'revisions', 'title'])
    expect(code.taxonomies).toEqual(['category', 'tag'])
    expect(Object.isFrozen(code)).toBe(true)
    expect(Object.isFrozen(code.labels)).toBe(true)
  })

  it('rejects route and REST contradictions at registration', () => {
    expect(() => normalizeContentTypeDefinition(contentType({ publiclyQueryable: false, hasArchive: true })))
      .toThrowError(expect.objectContaining<Partial<ContentDefinitionError>>({ code: 'invalid-definition', field: 'hasArchive' }))
    expect(() => normalizeContentTypeDefinition(contentType({ supports: ['title'], template: [{ type: 'core/paragraph' }] })))
      .toThrowError(expect.objectContaining<Partial<ContentDefinitionError>>({ code: 'invalid-definition', field: 'template' }))
    expect(() => normalizeContentTypeDefinition(contentType({ supports: ['title', 'editor'], rest: { base: 'articles', namespace: 'content/v1', revisions: true, autosaves: false } })))
      .toThrowError(expect.objectContaining<Partial<ContentDefinitionError>>({ code: 'invalid-definition', field: 'rest.revisions' }))
  })

  it('keeps the definition key immutable by excluding it from patches at the public type seam', () => {
    const normalized = normalizeContentTypeDefinition(contentType())
    expect(normalized.key).toBe('article')
    expect(normalized.defaultTemplateKey).toBe('article-default')
  })
})
