/**
 * AIContextManager Tests
 */

import { existsSync, mkdirSync, rmSync, writeFileSync, readFileSync } from 'fs'
import { join } from 'path'
import { tmpdir } from 'os'
import { AIContextManager } from '../manager'

describe('AIContextManager', () => {
  const testDir = join(tmpdir(), 'oculum-ai-context-test-' + Date.now())

  beforeAll(() => {
    // Create test directory
    mkdirSync(testDir, { recursive: true })
  })

  afterAll(() => {
    // Clean up test directory
    try {
      rmSync(testDir, { recursive: true, force: true })
    } catch {
      // Ignore cleanup errors
    }
  })

  beforeEach(() => {
    // Clean up .oculum directory before each test
    const oculumDir = join(testDir, '.oculum')
    try {
      rmSync(oculumDir, { recursive: true, force: true })
    } catch {
      // Ignore errors
    }
  })

  describe('saveContext', () => {
    it('should create .oculum directory if not exists', () => {
      const manager = new AIContextManager({ projectPath: testDir })
      const content = '# AI Context\n\nTest content'

      const result = manager.saveContext(content)

      expect(result.success).toBe(true)
      expect(existsSync(join(testDir, '.oculum'))).toBe(true)
      expect(existsSync(join(testDir, '.oculum', 'ai-context.md'))).toBe(true)
    })

    it('should save ai-context.md and return { success, path }', () => {
      const manager = new AIContextManager({ projectPath: testDir })
      const content = '# Security Issues\n\n1. SQL Injection in users.ts:42'

      const result = manager.saveContext(content)

      expect(result.success).toBe(true)
      expect(result.path).toBe(join(testDir, '.oculum', 'ai-context.md'))

      const savedContent = readFileSync(result.path, 'utf-8')
      expect(savedContent).toBe(content)
    })

    it('should overwrite existing ai-context.md', () => {
      const manager = new AIContextManager({ projectPath: testDir })

      // Save initial content
      manager.saveContext('Initial content')

      // Save new content
      const newContent = 'Updated content'
      const result = manager.saveContext(newContent)

      expect(result.success).toBe(true)
      const savedContent = readFileSync(result.path, 'utf-8')
      expect(savedContent).toBe(newContent)
    })

    it('should return { success: false, error } on permission error', () => {
      // Use an invalid path that will cause an error
      const manager = new AIContextManager({ projectPath: '/nonexistent/path/that/does/not/exist' })

      const result = manager.saveContext('test content')

      expect(result.success).toBe(false)
      expect(result.error).toBeDefined()
      expect(result.error).toContain('Failed to save')
    })
  })

  describe('loadContext', () => {
    it('should load existing context file', () => {
      const manager = new AIContextManager({ projectPath: testDir })
      const content = '# AI Context\n\nSome security findings'

      // Save first
      manager.saveContext(content)

      // Load
      const result = manager.loadContext()

      expect(result.found).toBe(true)
      expect(result.content).toBe(content)
    })

    it('should return { found: false } when file does not exist', () => {
      const manager = new AIContextManager({ projectPath: testDir })

      const result = manager.loadContext()

      expect(result.found).toBe(false)
      expect(result.content).toBeUndefined()
    })

    it('should return error if file cannot be read', () => {
      // Create a directory with the same name as the file (to cause read error)
      const oculumDir = join(testDir, '.oculum')
      const contextPath = join(oculumDir, 'ai-context.md')

      mkdirSync(oculumDir, { recursive: true })
      mkdirSync(contextPath, { recursive: true }) // Create as directory

      const manager = new AIContextManager({ projectPath: testDir })
      const result = manager.loadContext()

      expect(result.found).toBe(false)
      expect(result.error).toBeDefined()
    })
  })

  describe('clearContext', () => {
    it('should clear context file and return { success: true, existed: true }', () => {
      const manager = new AIContextManager({ projectPath: testDir })

      // Save first
      manager.saveContext('Some content')
      expect(manager.hasContext()).toBe(true)

      // Clear
      const result = manager.clearContext()

      expect(result.success).toBe(true)
      expect(result.existed).toBe(true)
      expect(manager.hasContext()).toBe(false)
    })

    it('should return { success: true, existed: false } when no context exists', () => {
      const manager = new AIContextManager({ projectPath: testDir })

      const result = manager.clearContext()

      expect(result.success).toBe(true)
      expect(result.existed).toBe(false)
    })
  })

  describe('hasContext', () => {
    it('should return true when ai-context.md exists', () => {
      const manager = new AIContextManager({ projectPath: testDir })
      manager.saveContext('test')

      expect(manager.hasContext()).toBe(true)
    })

    it('should return false when ai-context.md does not exist', () => {
      const manager = new AIContextManager({ projectPath: testDir })

      expect(manager.hasContext()).toBe(false)
    })
  })

  describe('getContextPath', () => {
    it('should return the full path to ai-context.md', () => {
      const manager = new AIContextManager({ projectPath: testDir })

      const path = manager.getContextPath()

      expect(path).toBe(join(testDir, '.oculum', 'ai-context.md'))
    })
  })

  describe('constructor', () => {
    it('should support string argument for backward compatibility', () => {
      const manager = new AIContextManager(testDir)

      expect(manager.getContextPath()).toBe(join(testDir, '.oculum', 'ai-context.md'))
    })

    it('should support options object', () => {
      const manager = new AIContextManager({ projectPath: testDir })

      expect(manager.getContextPath()).toBe(join(testDir, '.oculum', 'ai-context.md'))
    })
  })
})
