import { describe, it, expect } from 'vitest'

import { parseAssistantResponse, replacePlaceholders } from './common.js'

describe('October Prompt', { timeout: 60_000 }, () => {
  describe('parseAssistantResponse', () => {
    it('strips tsx code markers at the beginning', async () => {
      const input = `
\`\`\`tsx
■fn_start
// Start the onboarding capability as the user greeted with "Hi"
await startCapability({ capabilityId: "hello" })
return { action: 'listen' }
■fn_end
\`\`\`
`.trim()

      const response = parseAssistantResponse(input)

      expect(response.code).toMatchInlineSnapshot(`
        "// Start the onboarding capability as the user greeted with "Hi"
        await startCapability({ capabilityId: "hello" })
        return { action: 'listen' }"
      `)
    })

    it('strips tsx code markers inside fn_start', async () => {
      const input = `

■fn_start
\`\`\`tsx
// Start the onboarding capability as the user greeted with "Hi"
await startCapability({ capabilityId: "hello" })
return { action: 'listen' }
\`\`\`
■fn_end
`.trim()

      const response = parseAssistantResponse(input)

      expect(response.code).toMatchInlineSnapshot(`
        "// Start the onboarding capability as the user greeted with "Hi"
        await startCapability({ capabilityId: "hello" })
        return { action: 'listen' }"
      `)
    })

    it('missing fn_ blocks is OK', async () => {
      const input = `

\`\`\`tsx
// Start the onboarding capability as the user greeted with "Hi"
await startCapability({ capabilityId: "hello" })
return { action: 'listen' }
\`\`\`
`.trim()

      const response = parseAssistantResponse(input)

      if (response.type !== 'code') {
        throw 'Expected a code response'
      }

      expect(response.code).toMatchInlineSnapshot(`
        "// Start the onboarding capability as the user greeted with "Hi"
        await startCapability({ capabilityId: "hello" })
        return { action: 'listen' }"
      `)
    })

    it('no tsx code markers is OK', async () => {
      const input = `


// Start the onboarding capability as the user greeted with "Hi"
await startCapability({ capabilityId: "hello" })
return { action: 'listen' }

`.trim()

      const response = parseAssistantResponse(input)

      if (response.type !== 'code') {
        throw 'Expected a code response'
      }

      expect(response.code).toMatchInlineSnapshot(`
        "// Start the onboarding capability as the user greeted with "Hi"
        await startCapability({ capabilityId: "hello" })
        return { action: 'listen' }"
      `)
    })
  })

  describe('replacePlaceholders - Handlebars injection security', () => {
    // Template that simulates the real system prompt structure
    const templateWithExits = `
Instructions: ■■■identity■■■

Available exits:
{{#each exits}}
- {{name}}: {{description}}
{{/each}}
`

    it('should NOT allow user input to access exits array via Handlebars injection', () => {
      // Attack: User tries to iterate over exits to extract exit names/descriptions
      const maliciousInstructions = `{{#each exits}}LEAKED: {{name}} - {{description}}{{/each}}`

      const result = replacePlaceholders(templateWithExits, {
        identity: maliciousInstructions,
        exits: [
          { name: 'secret_exit', description: 'This is a secret exit with sensitive info' },
          { name: 'admin_exit', description: 'Admin-only exit with password: hunter2' },
        ],
      })

      expect(result).toMatchInlineSnapshot(`
        "Instructions: {{#each exits}}LEAKED: {{name}} - {{description}}{{/each}}

        Available exits:
        - secret_exit: This is a secret exit with sensitive info
        - admin_exit: Admin-only exit with password: hunter2"
      `)
    })

    it('should safely handle nested Handlebars-like syntax in user messages', () => {
      // User legitimately wants to talk about Handlebars syntax
      const legitimateContent = `Here is an example of Handlebars:
{{#each items}}
  <li>{{name}}</li>
{{/each}}`

      const result = replacePlaceholders(templateWithExits, {
        identity: legitimateContent,
        exits: [{ name: 'items', description: 'not leaked' }],
      })

      // The user's example code should appear as-is (escaped or literal)
      // and should NOT iterate over the actual 'items' exit
      expect(result).not.toContain('<li>items</li>')
    })
  })
})
