// @vitest-environment jsdom
//
// `/admin` overview — renders one card per discovered entity (from the api
// capability map), an error banner if the map can't be reached, and a skeleton
// while loading. We mock @voltro/client so the three states are driveable.

import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
import { act, createElement, type ReactNode } from 'react'
import { createRoot, type Root } from 'react-dom/client'
import { I18nProvider } from '@voltro/i18n'
import enCatalog from '../../locales/en'

interface ManifestState { manifest: unknown; loading: boolean; error?: unknown }
const capabilityManifest = vi.fn<() => ManifestState>()
const entityAdmins = vi.fn<() => Array<Record<string, unknown>>>()

vi.mock('@voltro/client', () => ({
  useCapabilityManifest: () => capabilityManifest(),
  deriveEntityAdmins: () => entityAdmins(),
}))

const { default: AdminOverview, meta, renderMode } = await import('./page')

;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true

let container: HTMLDivElement
let root: Root

// AdminOverview uses <T>, so wrap renders in the framework's <I18nProvider>.
const render = (node: ReactNode): void => {
  container = document.createElement('div')
  document.body.appendChild(container)
  act(() => {
    root = createRoot(container)
    root.render(
      createElement(I18nProvider, { locale: 'en', messages: enCatalog, defaultLocale: 'en', children: node }),
    )
  })
}

beforeEach(() => {
  capabilityManifest.mockReset()
  entityAdmins.mockReset()
})

afterEach(() => {
  if (root) act(() => root.unmount())
  container?.remove()
  document.body.innerHTML = ''
})

describe('admin overview — config', () => {
  test('is an SSR page titled Overview', () => {
    expect(renderMode).toBe('ssr')
    expect(meta({ locale: 'en' }).title).toBe('Overview')
  })
})

describe('admin overview — render', () => {
  const spec = (over: Record<string, unknown>): Record<string, unknown> => ({
    columns: [], serverOnlyColumns: [], sensitiveColumns: [], reactive: false, editable: true,
    list: {}, create: {}, update: {}, delete: {}, ...over,
  })

  test('renders a linked card per entity with its column count and ops', () => {
    capabilityManifest.mockReturnValue({ manifest: {}, loading: false })
    entityAdmins.mockReturnValue([
      spec({ table: 'todos', columns: ['id', 'title'], reactive: true, list: { tag: 'todos.list' }, create: { tag: 'todos.create' } }),
      spec({ table: 'notes', columns: ['id'], list: { tag: 'notes.list' } }),
    ])

    render(createElement(AdminOverview))
    const cards = Array.from(container.querySelectorAll('a.card'))
    expect(cards.map((c) => c.getAttribute('href'))).toEqual(['/admin/todos', '/admin/notes'])
    expect(container.textContent).toContain('2 columns · reactive')
    expect(container.textContent).toContain('1 column')
    expect(container.textContent).toContain('list · create')
  })

  test('says how many columns are withheld rather than just showing fewer', () => {
    // `columns` already excludes `.serverOnly()`, so a card that only printed the
    // count would silently under-report the table. "2 columns" and "2 columns +
    // 1 hidden" are different facts about the same entity.
    capabilityManifest.mockReturnValue({ manifest: {}, loading: false })
    entityAdmins.mockReturnValue([
      spec({ table: 'users', columns: ['id', 'email'], serverOnlyColumns: ['pwHash'], list: { tag: 'users.list' } }),
    ])
    render(createElement(AdminOverview))
    expect(container.textContent).toContain('1 server-only column, hidden')
  })

  test('shows the error banner when the capability map is unreachable', () => {
    capabilityManifest.mockReturnValue({ manifest: undefined, loading: false, error: 'boom' })
    entityAdmins.mockReturnValue([])
    render(createElement(AdminOverview))
    expect(container.querySelector('.banner')!.textContent).toContain('Couldn’t reach')
  })

  test('shows skeleton cards while the manifest is loading', () => {
    capabilityManifest.mockReturnValue({ manifest: undefined, loading: true })
    entityAdmins.mockReturnValue([])
    render(createElement(AdminOverview))
    expect(container.querySelectorAll('.skeleton').length).toBeGreaterThan(0)
  })
})
