import {describe, it, expect} from 'vitest'
import * as path from 'path'
import {fileURLToPath} from 'url'
import {
  parseTemplateVariables,
  replaceTemplateVariables,
  loadPromptFile,
  isPromptYamlFile,
  parseFileTemplateVariables,
} from '../src/prompt'

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)

describe('prompt.ts', () => {
  describe('parseTemplateVariables', () => {
    it('should parse simple YAML variables', () => {
      const input = `
 a: hello
 b: world
      `
      const result = parseTemplateVariables(input)
      expect(result).toEqual({a: 'hello', b: 'world'})
    })

    it('should parse multiline variables', () => {
      const input = `
 var1: hello
 var2: |
   This is a
   multiline string
      `
      const result = parseTemplateVariables(input)
      expect(result.var1).toBe('hello')
      expect(result.var2).toContain('This is a')
      expect(result.var2).toContain('multiline string')
    })

    it('should return empty object for empty input', () => {
      const result = parseTemplateVariables('')
      expect(result).toEqual({})
    })

    it('should throw error for invalid YAML', () => {
      const input = 'invalid: yaml: content:'
      expect(() => parseTemplateVariables(input)).toThrow()
    })
  })

  describe('replaceTemplateVariables', () => {
    it('should replace simple variables', () => {
      const text = 'Hello {{name}}, welcome to {{place}}!'
      const variables = {name: 'John', place: 'GitHub'}
      const result = replaceTemplateVariables(text, variables)
      expect(result).toBe('Hello John, welcome to GitHub!')
    })

    it('should leave unreplaced variables as is', () => {
      const text = 'Hello {{name}}, welcome to {{unknown}}!'
      const variables = {name: 'John'}
      const result = replaceTemplateVariables(text, variables)
      expect(result).toBe('Hello John, welcome to {{unknown}}!')
    })

    it('should handle no variables', () => {
      const text = 'No variables here'
      const variables = {}
      const result = replaceTemplateVariables(text, variables)
      expect(result).toBe('No variables here')
    })
  })

  describe('isPromptYamlFile', () => {
    it('should detect .prompt.yml files', () => {
      expect(isPromptYamlFile('test.prompt.yml')).toBe(true)
      expect(isPromptYamlFile('path/to/test.prompt.yml')).toBe(true)
    })

    it('should detect .prompt.yaml files', () => {
      expect(isPromptYamlFile('test.prompt.yaml')).toBe(true)
      expect(isPromptYamlFile('path/to/test.prompt.yaml')).toBe(true)
    })

    it('should reject other file types', () => {
      expect(isPromptYamlFile('test.txt')).toBe(false)
      expect(isPromptYamlFile('test.yml')).toBe(false)
      expect(isPromptYamlFile('test.yaml')).toBe(false)
      expect(isPromptYamlFile('test.prompt')).toBe(false)
    })
  })

  describe('loadPromptFile', () => {
    it('should load simple prompt file', () => {
      const filePath = path.join(__dirname, '../__fixtures__/prompts/simple.prompt.yml')
      const variables = {a: 'cats', b: 'dogs'}
      const result = loadPromptFile(filePath, variables)

      expect(result.messages).toHaveLength(2)
      expect(result.messages[0]).toEqual({
        role: 'system',
        content: 'Be as concise as possible',
      })
      expect(result.messages[1]).toEqual({
        role: 'user',
        content: 'Compare cats and dogs, please',
      })
      expect(result.model).toBe('openai/gpt-4o')
    })

    it('should load JSON schema prompt file', () => {
      const filePath = path.join(__dirname, '../__fixtures__/prompts/json-schema.prompt.yml')
      const variables = {animal: 'dog'}
      const result = loadPromptFile(filePath, variables)

      expect(result.messages).toHaveLength(2)
      expect(result.messages[1].content).toContain('Describe a dog')
      expect(result.responseFormat).toBe('json_schema')
      expect(result.jsonSchema).toBeDefined()
      expect(result.jsonSchema).toContain('describe_animal')
    })

    it('should throw error for non-existent file', () => {
      expect(() => loadPromptFile('non-existent.prompt.yml')).toThrow('Prompt file not found')
    })
  })

  describe('parseFileTemplateVariables', () => {
    it('reads file contents for variables', () => {
      const configPath = path.join(__dirname, '../__fixtures__/prompts/json-schema.prompt.yml')
      const data = parseFileTemplateVariables(`sample: ${configPath}`)
      expect(data.sample).toContain('messages:')
      expect(data.sample).toContain('responseFormat:')
    })

    it('errors on missing files', () => {
      expect(() => parseFileTemplateVariables('x: ./does-not-exist.txt')).toThrow('was not found')
    })

    it('errors on non-string file paths', () => {
      expect(() => parseFileTemplateVariables('x: 123')).toThrow(
        "File template variable 'x' must be a string file path",
      )
      expect(() => parseFileTemplateVariables('x: true')).toThrow(
        "File template variable 'x' must be a string file path",
      )
      expect(() => parseFileTemplateVariables('x: { nested: "object" }')).toThrow(
        "File template variable 'x' must be a string file path",
      )
    })
  })
})
