// @vitest-environment jsdom
//
// The dashboard shell + AUTH GATE. The loader redirects an unauthenticated
// request (throws RedirectError) and otherwise returns the shared user data the
// layout renders. We mock the framework hooks (useLoaderData / useLocation) so
// the render is standalone, and import the REAL RedirectError so the loader's
// throw is observable.

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

const loaderData = vi.fn<() => unknown>()
const location = vi.fn<() => string>()

vi.mock('@voltro/web', async () => {
  const actual = await vi.importActual<typeof import('@voltro/web')>('@voltro/web')
  return { ...actual, useLoaderData: () => loaderData(), useLocation: () => location() }
})

const { default: DashboardLayout, loader } = await import('./layout')

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

let container: HTMLDivElement
let root: Root

// DashboardLayout uses <T>/useLocale + <LocaleSwitcher>, so wrap renders in the
// framework's <I18nProvider> (auto-wired in the running app).
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 }),
    )
  })
}

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

describe('dashboard layout — loader (auth gate)', () => {
  test('redirects to /login (remembering the destination) when no session cookie is present', async () => {
    const err = await Promise.resolve(loader({ headers: {} } as never)).catch((e: unknown) => e)
    expect(err).toBeInstanceOf(RedirectError)
    expect((err as RedirectError).location).toBe('/login?from=/dashboard')
  })

  test('returns the shared user for a signed-in request', async () => {
    const data = await loader({ headers: { cookie: 'demo_session=ok' } } as never)
    expect(data.user.name).toBe('Demo User')
    expect(data.user.plan).toBe('Pro')
  })
})

describe('dashboard layout — render', () => {
  test('renders the user, plan, and nav links', () => {
    loaderData.mockReturnValue({ user: { name: 'Ada', plan: 'Enterprise' } })
    location.mockReturnValue('/dashboard')
    render(createElement(DashboardLayout, { children: createElement('p', null, 'page body') }))
    expect(container.textContent).toContain('Ada')
    expect(container.textContent).toContain('Enterprise plan')
    const hrefs = Array.from(container.querySelectorAll('a')).map((a) => a.getAttribute('href'))
    expect(hrefs).toContain('/dashboard')
    expect(hrefs).toContain('/dashboard/settings')
    expect(container.querySelector('main')!.textContent).toContain('page body')
  })

  test('marks the active nav link with aria-current for the current path', () => {
    loaderData.mockReturnValue({ user: { name: 'Ada', plan: 'Pro' } })
    location.mockReturnValue('/dashboard/settings')
    render(createElement(DashboardLayout, { children: null }))
    const active = Array.from(container.querySelectorAll('a')).find(
      (a) => a.getAttribute('aria-current') === 'page',
    )!
    expect(active.getAttribute('href')).toBe('/dashboard/settings')
  })
})
