import { describe, expect, test } from 'vitest'
import heroDemoRequests from '../../src/components/pages/home/hero-demo-requests.js'
import { sourceHarness } from '../utils/eval-source.mjs'

const { slice, evaluate: rawEvaluate } = sourceHarness(
  'src/components/pages/home/hero/constants.js'
)

const { source: composer, slice: composerSlice } = sourceHarness(
  'src/components/pages/home/hero/composer.js'
)

const { source: hero, slice: heroSlice } = sourceHarness(
  'src/components/pages/home/hero/index.js'
)

const evaluate = (code, name) => rawEvaluate(code, name, { heroDemoRequests })

const PROMPTS = evaluate(slice('const PROMPTS', 'const PARSE_RULES'), 'PROMPTS')
const parseLocal = evaluate(
  slice('const PARSE_RULES', 'const DEFAULT_URLS'),
  'parseLocal'
)

const derived = name =>
  evaluate(
    [
      "const SEARCH_EXAMPLE = { query: 'query' }",
      'const { shortUrl } = heroDemoRequests',
      slice('const PROMPTS', 'const PARSE_RULES'),
      slice('const DEFAULT_URLS', 'const assertProductParity'),
      slice('const promptFor', 'const VERT_BORDER_ACTIVE')
    ].join('\n'),
    name
  )

const CYCLE = derived('CYCLE')
const EXAMPLE_CHIPS = derived('EXAMPLE_CHIPS')

const MAPS = evaluate(
  [
    'const { FN_SNIPPET, REQUEST_OPTS } = heroDemoRequests',
    slice('const AGENT_TASK', 'const agentPrompt'),
    slice('const INSTALL_COMMENT', 'const PROMPTS')
  ].join('\n'),
  '({ AGENT_TASK, REQUEST_OPTS, CODE_TAB })'
)

describe('home hero prompts', () => {
  test('example chips use the terse naming', () => {
    expect(EXAMPLE_CHIPS.map(chip => chip.text)).toEqual([
      'take screenshot',
      'detect technologies',
      'extract metadata',
      'get markdown',
      'grab logo'
    ])
  })

  test('per-vertical maps stay key-synced with PROMPTS', () => {
    const keys = Object.keys(PROMPTS).sort()
    expect(Object.keys(MAPS.REQUEST_OPTS).sort()).toEqual(keys)
    expect(Object.keys(MAPS.CODE_TAB).sort()).toEqual(keys)
    expect(Object.keys(MAPS.AGENT_TASK).sort()).toEqual(
      keys.filter(key => key !== 'search')
    )
  })

  test('every product prompt parses back to its vertical', () => {
    for (const [vertical, prompt] of Object.entries(PROMPTS)) {
      expect({ prompt, vertical: parseLocal(prompt).vertical }).toEqual({
        prompt,
        vertical
      })
    }
  })

  test('every example chip parses to its own vertical', () => {
    expect(EXAMPLE_CHIPS.map(chip => chip.vertical)).toEqual([
      'screenshot',
      'technologies',
      'metadata',
      'markdown',
      'logo'
    ])
    EXAMPLE_CHIPS.forEach(({ text, vertical }) => {
      expect(parseLocal(text).vertical).toBe(vertical)
    })
  })

  test('every typing-cycle sentence parses to the intended vertical', () => {
    const want = [
      'screenshot',
      'pdf',
      'lighthouse',
      'technologies',
      'text',
      'function',
      'markdown',
      'logo'
    ]
    CYCLE.forEach((text, i) => {
      expect(parseLocal(text).vertical).toBe(want[i])
    })
  })

  test('composer renders the URL as an atomic chip in a contenteditable', () => {
    expect(composer).toContain('contentEditable')
    expect(composer).toContain('composerHtml(dSegments')
    expect(composer).toContain('contenteditable="false"')
    expect(composer).toContain('dangerouslySetInnerHTML')
    const editor = composerSlice('const ComposerEditor', 'const CLOSE_ICON_SVG')
    expect(editor).toContain('[data-url-tag]')
    expect(editor).not.toContain('grape')
  })

  test('url chip uses the docs inline-code style', () => {
    const editor = composerSlice('const ComposerEditor', 'const CLOSE_ICON_SVG')
    const tag = editor.slice(editor.indexOf('[data-url-tag]'))
    expect(tag).toContain("color: 'secondary'")
    expect(tag).toContain("fontFamily: 'mono'")
    expect(tag).toContain("fontWeight: 'normal'")
    expect(tag).toContain('text-shadow: rgba(0, 0, 0, 0.05) 0px 1px')
    expect(tag).not.toContain('content:')
    expect(composer).not.toContain('LINK_ICON_SVG')
  })

  test('url chip reveals a remove button on hover', () => {
    expect(composer).toContain('aria-label="Remove URL"')
    expect(composer).toContain('removeUrl()')
    const editor = composerSlice('const ComposerEditor', 'const CLOSE_ICON_SVG')
    expect(editor).toContain('[data-url-tag]:hover [data-url-action]')
    const remove = heroSlice('const removeUrl', 'const pickExample')
    expect(remove).toContain('.replace(raw, ')
    expect(remove).toContain('.focus()')
  })

  test('focusing mid-animation completes the current example', () => {
    const focus = heroSlice('const onEditorFocus', 'useIsomorphicLayoutEffect(')
    expect(focus).toContain('anim.current.userTook')
    expect(focus).toContain('CYCLE[anim.current.ci]')
    expect(focus).toContain('pendingCaret.current = target.length')
  })

  test('caret survives re-renders via offset save and restore', () => {
    expect(composer).toContain('const getCaretOffset')
    expect(composer).toContain('const setCaretOffset')
    expect(hero).toContain('pendingCaret.current = getCaretOffset(el)')
    expect(hero).toContain('setCaretOffset(el, pendingCaret.current)')
  })
})
