// @vitest-environment jsdom
//
// `/` SSR-fed-by-the-api page. The loader pulls `notes.list` from the api's
// rpc via the server-only `query` fn; `meta` is a function of the loader data
// so the <title> reflects the real row count. The component renders the SSR'd
// snapshot, then upgrades to `useSubscription` on the client. We mock
// `@voltro/web` (loader hook) + `@voltro/client` (subscription).

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'

const loaderData = vi.fn<() => unknown>()
const useSubscription = vi.fn<() => { data: unknown }>()
vi.mock('@voltro/web', () => ({ useLoaderData: () => loaderData() }))
vi.mock('@voltro/client', () => ({ useSubscription: () => useSubscription() }))

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

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

interface Note { id: string; title: string; body: string; done: boolean }

let container: HTMLDivElement
let root: Root

// The page uses <T>, so it needs an <I18nProvider> (real English catalog).
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(() => {
  loaderData.mockReset()
  useSubscription.mockReset()
  useSubscription.mockReturnValue({ data: undefined })
})

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

const sample: ReadonlyArray<Note> = [
  { id: 'n_1', title: 'First note', body: 'hello', done: false },
  { id: 'n_2', title: 'Second note', body: '', done: true },
]

describe('index — loader', () => {
  test('drains `notes.list` from the api via the server-side query fn', async () => {
    const query = vi.fn(async () => sample)
    const data = await loader({ query } as never)
    expect(query).toHaveBeenCalledWith('notes.list', {})
    expect(data.notes).toEqual(sample)
  })

  test('returns an empty list when no server-side query fn is present (client nav)', async () => {
    const data = await loader({ query: undefined } as never)
    expect(data.notes).toEqual([])
  })
})

describe('index — meta', () => {
  test('bakes the row count into the <title>', () => {
    expect(renderMode).toBe('ssr')
    expect(meta({ locale: 'en', loaderData: { notes: sample } }).title).toContain('2 notes')
  })
})

describe('index — render', () => {
  test('renders the SSR snapshot rows when the subscription has no data yet', () => {
    loaderData.mockReturnValue({ notes: sample })
    render(createElement(Home))
    const items = Array.from(container.querySelectorAll('li'))
    expect(items).toHaveLength(2)
    expect(container.textContent).toContain('First note')
    expect(container.textContent).toContain('✓ done')
  })

  test('the live subscription data overrides the SSR snapshot once connected', () => {
    loaderData.mockReturnValue({ notes: sample })
    useSubscription.mockReturnValue({
      data: [{ id: 'n_9', title: 'Live note', body: '', done: false }],
    })
    render(createElement(Home))
    const items = Array.from(container.querySelectorAll('li'))
    expect(items).toHaveLength(1)
    expect(container.textContent).toContain('Live note')
  })

  test('shows the empty state when there are no notes', () => {
    loaderData.mockReturnValue({ notes: [] })
    render(createElement(Home))
    expect(container.textContent).toContain('No notes yet')
  })
})
