// @vitest-environment happy-dom
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { render, screen } from '@testing-library/react'
import {
  SectionRenderer,
  AdminSectionRenderersProvider,
  type AdminSectionRendererMap,
} from '../../views/page-editor/sections/index.js'
import type { PageSection } from '../../lib/page-editor-service.js'

function customSection(overrides: Partial<PageSection> = {}): PageSection {
  return {
    id: 's1',
    sectionType: 'opal-flip-cards',
    name: 'Flip Cards',
    visible: true,
    content: { heading: 'Why us' },
    settings: {},
    ...overrides,
  }
}

describe('pluggable admin section renderers', () => {
  it('renders the structural placeholder when no renderer is registered', () => {
    render(<SectionRenderer section={customSection()} />)
    expect(screen.getByText(/Custom section "opal-flip-cards"/)).toBeTruthy()
  })

  it('renders a registered custom renderer instead of the placeholder', () => {
    const renderers: AdminSectionRendererMap = {
      'opal-flip-cards': ({ section }) => (
        <div data-testid="opal-renderer">{String(section.content?.heading)}</div>
      ),
    }
    render(
      <AdminSectionRenderersProvider value={renderers}>
        <SectionRenderer section={customSection()} />
      </AdminSectionRenderersProvider>,
    )
    expect(screen.getByTestId('opal-renderer').textContent).toBe('Why us')
    expect(screen.queryByText(/Custom section "opal-flip-cards"/)).toBeNull()
  })

  it('passes the resolved render options to the custom renderer', () => {
    const seen: unknown[] = []
    const renderers: AdminSectionRendererMap = {
      'opal-flip-cards': ({ options }) => {
        seen.push(options)
        return <div>{options.renderImage({ src: '/x.png', alt: 'x' })}</div>
      },
    }
    render(
      <AdminSectionRenderersProvider value={renderers}>
        <SectionRenderer section={customSection()} />
      </AdminSectionRenderersProvider>,
    )
    const options = seen[0] as { sanitizeHtml: (h: string) => string; baseUrl: string }
    expect(options.sanitizeHtml('<b>x</b>')).toBe('<b>x</b>')
    expect(options.baseUrl).toBe('')
    expect(screen.getByAltText('x')).toBeTruthy()
  })

  describe('throwing renderers', () => {
    beforeEach(() => {
      // React logs boundary-caught errors; keep test output clean.
      vi.spyOn(console, 'error').mockImplementation(() => {})
    })
    afterEach(() => {
      vi.restoreAllMocks()
    })

    it('falls back to the structural placeholder instead of crashing the canvas', () => {
      const renderers: AdminSectionRendererMap = {
        'opal-flip-cards': () => {
          throw new Error('consumer renderer exploded')
        },
      }
      render(
        <AdminSectionRenderersProvider value={renderers}>
          <SectionRenderer section={customSection()} />
        </AdminSectionRenderersProvider>,
      )
      expect(screen.getByText(/Custom section "opal-flip-cards"/)).toBeTruthy()
    })
  })

  it('does not affect built-in section types', () => {
    const renderers: AdminSectionRendererMap = {
      hero: () => <div data-testid="hijacked-hero" />,
    }
    render(
      <AdminSectionRenderersProvider value={renderers}>
        <SectionRenderer
          section={customSection({ sectionType: 'hero', name: 'Hero', content: {} })}
        />
      </AdminSectionRenderersProvider>,
    )
    // Built-in types always use the built-in canvas component.
    expect(screen.queryByTestId('hijacked-hero')).toBeNull()
  })
})
