// @vitest-environment happy-dom
import { afterEach, describe, expect, it, vi } from 'vitest'
import { render, screen } from '@testing-library/react'

const fetchPageForEditor = vi.fn()
vi.mock('../../lib/page-editor-service.js', async (importOriginal) => {
  const actual = await importOriginal<typeof import('../../lib/page-editor-service.js')>()
  return {
    ...actual,
    fetchPageForEditor: (...args: unknown[]) => fetchPageForEditor(...args),
  }
})

const { PageSectionEditor } = await import('../../views/page-editor/PageSectionEditor.js')
const { AdminSectionRenderersProvider } = await import('../../views/page-editor/sections/index.js')

const validConfig = {
  collections: {
    pages: {
      slug: 'pages',
      fields: {
        title: { type: 'text' },
        slug: { type: 'slug' },
        path: { type: 'text' },
        sections: { type: 'json' },
        metaTitle: { type: 'text' },
        metaDescription: { type: 'text' },
      },
    },
  },
}

afterEach(() => {
  fetchPageForEditor.mockReset()
})

describe('PageSectionEditor schema guard', () => {
  it('refuses to operate when the pages collection is missing the sections field', async () => {
    const badConfig = {
      collections: { pages: { slug: 'pages', fields: { title: { type: 'text' } } } },
    }

    render(
      <PageSectionEditor documentId="p1" config={badConfig} onNavigate={() => {}} session={{}} />,
    )

    expect(await screen.findByText(/missing required field/i)).toBeTruthy()
    expect(screen.getByText(/sections/)).toBeTruthy()
    // The guard must short-circuit before any network read.
    expect(fetchPageForEditor).not.toHaveBeenCalled()
  })

  it('does not block when no config is provided (embedding/test contexts)', async () => {
    render(<PageSectionEditor config={undefined} onNavigate={() => {}} session={{}} />)
    // New page (no documentId) → empty editor shell renders.
    expect(await screen.findByText('Sections')).toBeTruthy()
  })
})

describe('PageSectionEditor new page', () => {
  it('renders the editor shell without fetching for /pages/new', async () => {
    render(<PageSectionEditor config={validConfig} onNavigate={() => {}} session={{}} />)
    expect(await screen.findByText('Sections')).toBeTruthy()
    expect(fetchPageForEditor).not.toHaveBeenCalled()
  })

  it('hides the version history button for unsaved pages', async () => {
    render(<PageSectionEditor config={validConfig} onNavigate={() => {}} session={{}} />)
    await screen.findByText('Sections')
    expect(screen.queryByRole('button', { name: 'Version history' })).toBeNull()
  })
})

function loadedPage(sections: Array<{ id: string; sectionType: string; name: string }>) {
  return {
    id: 'p1',
    title: 'Home',
    slug: 'home',
    path: '/home',
    status: 'DRAFT',
    sections: sections.map((s) => ({ ...s, visible: true, content: {}, settings: {} })),
    seoTitle: '',
    seoDescription: '',
    publishedAt: null,
    updatedAt: null,
    builderOwned: false,
  }
}

describe('PageSectionEditor structure mode', () => {
  it('stays out of structure mode when every section has a canvas renderer', async () => {
    fetchPageForEditor.mockResolvedValue(
      loadedPage([{ id: 's1', sectionType: 'hero', name: 'Hero' }]),
    )
    render(
      <PageSectionEditor documentId="p1" config={validConfig} onNavigate={() => {}} session={{}} />,
    )

    await screen.findByText('Sections')
    expect(screen.queryByText(/Structure view/)).toBeNull()
    // "View on site" stays an icon-only button.
    expect(screen.getByRole('button', { name: 'View draft on site' })).toBeTruthy()
    expect(screen.getByRole('button', { name: 'Preview page' })).toBeTruthy()
  })

  it('shows the structure notice and promotes "View on site" for custom section types', async () => {
    fetchPageForEditor.mockResolvedValue(
      loadedPage([
        { id: 's1', sectionType: 'hero', name: 'Hero' },
        { id: 's2', sectionType: 'opal-flip-cards', name: 'Flip Cards' },
      ]),
    )
    render(
      <PageSectionEditor documentId="p1" config={validConfig} onNavigate={() => {}} session={{}} />,
    )

    await screen.findByText('Sections')
    expect(screen.getByText(/Structure view/)).toBeTruthy()
    // Promoted to a labeled button — the primary design preview.
    expect(screen.getByRole('button', { name: /View on site/ })).toBeTruthy()
    // Eye preview is relabeled to set expectations.
    expect(screen.getByRole('button', { name: /Preview structure/ })).toBeTruthy()
  })

  it('stays out of structure mode when a custom renderer is registered for the type', async () => {
    fetchPageForEditor.mockResolvedValue(
      loadedPage([
        { id: 's1', sectionType: 'hero', name: 'Hero' },
        { id: 's2', sectionType: 'opal-flip-cards', name: 'Flip Cards' },
      ]),
    )
    render(
      <AdminSectionRenderersProvider
        value={{ 'opal-flip-cards': () => <div data-testid="opal-canvas" /> }}
      >
        <PageSectionEditor
          documentId="p1"
          config={validConfig}
          onNavigate={() => {}}
          session={{}}
        />
      </AdminSectionRenderersProvider>,
    )

    await screen.findByText('Sections')
    // The registered renderer draws the section, so the canvas is no longer
    // structural for this page.
    expect(screen.getByTestId('opal-canvas')).toBeTruthy()
    expect(screen.queryByText(/Structure view/)).toBeNull()
    expect(screen.getByRole('button', { name: 'View draft on site' })).toBeTruthy()
  })

  it('exposes a version history button for saved pages', async () => {
    fetchPageForEditor.mockResolvedValue(
      loadedPage([{ id: 's1', sectionType: 'hero', name: 'Hero' }]),
    )
    render(
      <PageSectionEditor documentId="p1" config={validConfig} onNavigate={() => {}} session={{}} />,
    )

    await screen.findByText('Sections')
    expect(screen.getByRole('button', { name: 'Version history' })).toBeTruthy()
  })
})
