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

/**
 * useSitePreview — drives the inline branded preview (iframe of the public
 * site rendering a draft). Pins: token minted + URL built on activation,
 * unsaved drafts are persisted first (a failed save cancels activation), and
 * the frame reloads (reloadKey bump) after each completed save.
 */

const createPreviewToken = vi.fn(async () => ({
  token: 'tok-123',
  expiresAt: '2026-06-19T00:00:00Z',
}))

vi.mock('../../lib/preview-link.js', () => ({
  createPreviewToken: (...args: unknown[]) => createPreviewToken(...(args as [])),
  buildPublicPreviewUrl: ({ siteUrl, urlPrefix, slug, token }: any) =>
    `${siteUrl}${urlPrefix ? `/${urlPrefix}` : ''}/${slug}?preview=${token}`,
  resolveSiteUrl: (u?: string | null) => u ?? 'https://fallback.test',
}))

vi.mock('sonner', () => ({
  toast: { error: vi.fn(), success: vi.fn() },
}))

const { useSitePreview } = await import('../../views/page-editor/useSitePreview.js')
const { toast } = await import('sonner')

import type { SaveState } from '../../views/page-editor/EditorTopBar.js'

function Harness({
  documentId = 'doc-1',
  slug = 'about',
  dirty = false,
  saveState = 'idle' as SaveState,
  saveDraft = vi.fn(async () => true),
}: {
  documentId?: string | null
  slug?: string | null
  dirty?: boolean
  saveState?: SaveState
  saveDraft?: () => Promise<boolean>
}) {
  const sp = useSitePreview({
    collection: 'pages',
    documentId,
    slug,
    urlPrefix: '',
    siteUrl: 'https://site.test',
    dirty,
    saveState,
    saveDraft,
  })
  return (
    <div>
      <button type="button" onClick={sp.toggle}>
        toggle
      </button>
      <output data-testid="state">
        {JSON.stringify({ active: sp.active, url: sp.url, reloadKey: sp.reloadKey })}
      </output>
    </div>
  )
}

function state(): { active: boolean; url: string | null; reloadKey: number } {
  return JSON.parse(screen.getByTestId('state').textContent ?? '{}')
}

beforeEach(() => {
  createPreviewToken.mockClear()
  vi.mocked(toast.error).mockClear()
})

describe('useSitePreview', () => {
  it('mints a token and builds the public draft URL on activation', async () => {
    render(<Harness />)
    fireEvent.click(screen.getByText('toggle'))
    expect(state().active).toBe(true)
    await waitFor(() => {
      expect(state().url).toBe('https://site.test/about?preview=tok-123')
    })
    expect(createPreviewToken).toHaveBeenCalledWith('pages', 'doc-1')
  })

  it('saves a dirty draft before minting; a failed save cancels activation', async () => {
    const saveDraft = vi.fn(async () => false)
    render(<Harness dirty saveDraft={saveDraft} />)
    fireEvent.click(screen.getByText('toggle'))
    await waitFor(() => expect(saveDraft).toHaveBeenCalled())
    await waitFor(() => expect(state().active).toBe(false))
    expect(createPreviewToken).not.toHaveBeenCalled()
  })

  it('refuses to activate for unsaved documents', () => {
    render(<Harness documentId={null} />)
    fireEvent.click(screen.getByText('toggle'))
    expect(state().active).toBe(false)
    expect(toast.error).toHaveBeenCalled()
  })

  it('toggles back to the canvas on second click', async () => {
    render(<Harness />)
    fireEvent.click(screen.getByText('toggle'))
    await waitFor(() => expect(state().url).not.toBeNull())
    fireEvent.click(screen.getByText('toggle'))
    expect(state().active).toBe(false)
  })

  it('bumps reloadKey after a save completes while the preview is open', async () => {
    const { rerender } = render(<Harness saveState="idle" />)
    fireEvent.click(screen.getByText('toggle'))
    await waitFor(() => expect(state().url).not.toBeNull())
    expect(state().reloadKey).toBe(0)

    rerender(<Harness saveState="saving" />)
    rerender(<Harness saveState="saved" />)
    await waitFor(() => expect(state().reloadKey).toBe(1))
  })
})
