/**
 * Baseline Manager Tests
 */

import { existsSync, mkdirSync, readFileSync, writeFileSync, rmSync } from 'fs'
import { join } from 'path'
import { tmpdir } from 'os'
import { BaselineManager } from '../manager'
import type { ScanResult } from '../../types'
import type { BaselineData } from '../types'

describe('BaselineManager', () => {
  let testDir: string
  let manager: BaselineManager

  beforeEach(() => {
    // Create a unique temp directory for each test
    testDir = join(tmpdir(), `baseline-test-${Date.now()}-${Math.random().toString(36).slice(2)}`)
    mkdirSync(testDir, { recursive: true })
    manager = new BaselineManager({ projectPath: testDir })
  })

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

  describe('loadBaseline', () => {
    it('should return found: false when no baseline exists', () => {
      const result = manager.loadBaseline()
      expect(result.found).toBe(false)
      expect(result.baseline).toBeUndefined()
      expect(result.error).toBeUndefined()
    })

    it('should load a valid baseline', () => {
      // Create a valid baseline file
      const baseline: BaselineData = {
        version: 1,
        createdAt: '2024-01-15T10:00:00.000Z',
        commit: 'abc1234',
        branch: 'main',
        findings: [
          {
            hash: 'abcd1234abcd1234',
            filePath: 'src/test.ts',
            lineNumber: 10,
            category: 'hardcoded_secret',
            severity: 'critical',
            title: 'Hardcoded API key',
          },
        ],
        stats: {
          total: 1,
          critical: 1,
          high: 0,
          medium: 0,
          low: 0,
          info: 0,
        },
      }

      mkdirSync(join(testDir, '.oculum'), { recursive: true })
      writeFileSync(join(testDir, '.oculum/baseline.json'), JSON.stringify(baseline))

      const result = manager.loadBaseline()
      expect(result.found).toBe(true)
      expect(result.baseline).toEqual(baseline)
      expect(result.error).toBeUndefined()
    })

    it('should return error for invalid JSON', () => {
      mkdirSync(join(testDir, '.oculum'), { recursive: true })
      writeFileSync(join(testDir, '.oculum/baseline.json'), 'not valid json')

      const result = manager.loadBaseline()
      expect(result.found).toBe(false)
      expect(result.error).toContain('Failed to parse baseline')
    })

    it('should return error for unsupported version', () => {
      const baseline = {
        version: 99,
        createdAt: '2024-01-15T10:00:00.000Z',
        findings: [],
        stats: { total: 0, critical: 0, high: 0, medium: 0, low: 0, info: 0 },
      }

      mkdirSync(join(testDir, '.oculum'), { recursive: true })
      writeFileSync(join(testDir, '.oculum/baseline.json'), JSON.stringify(baseline))

      const result = manager.loadBaseline()
      expect(result.found).toBe(false)
      expect(result.error).toContain('Unsupported baseline version')
    })

    it('should return error when findings array is missing', () => {
      const baseline = {
        version: 1,
        createdAt: '2024-01-15T10:00:00.000Z',
        stats: { total: 0, critical: 0, high: 0, medium: 0, low: 0, info: 0 },
      }

      mkdirSync(join(testDir, '.oculum'), { recursive: true })
      writeFileSync(join(testDir, '.oculum/baseline.json'), JSON.stringify(baseline))

      const result = manager.loadBaseline()
      expect(result.found).toBe(false)
      expect(result.error).toContain('missing findings array')
    })
  })

  describe('saveBaseline', () => {
    it('should save a baseline from scan result', () => {
      const scanResult: ScanResult = {
        repoName: 'test/repo',
        repoUrl: 'https://github.com/test/repo',
        branch: 'main',
        filesScanned: 10,
        filesSkipped: 2,
        vulnerabilities: [
          {
            filePath: 'src/test.ts',
            lineNumber: 10,
            category: 'hardcoded_secret',
            severity: 'critical',
            title: 'Hardcoded API key',
            description: 'Test description',
            confidence: 'high',
            layer: 1,
            lineContent: 'const API_KEY = "sk-1234567890"',
          },
        ],
        severityCounts: { critical: 1, high: 0, medium: 0, low: 0, info: 0 },
        categoryCounts: {},
        hasBlockingIssues: true,
        scanDuration: 1000,
        timestamp: '2024-01-15T10:00:00.000Z',
      }

      const result = manager.saveBaseline(scanResult, { scanDepth: 'local' })

      expect(result.success).toBe(true)
      expect(existsSync(result.path)).toBe(true)

      // Verify saved content
      const content = readFileSync(result.path, 'utf-8')
      const baseline = JSON.parse(content) as BaselineData

      expect(baseline.version).toBe(1)
      expect(baseline.findings).toHaveLength(1)
      expect(baseline.findings[0].title).toBe('Hardcoded API key')
      expect(baseline.stats.critical).toBe(1)
      expect(baseline.scanDepth).toBe('local')
    })

    it('should create .oculum directory if it does not exist', () => {
      const scanResult: ScanResult = {
        repoName: 'test/repo',
        repoUrl: 'https://github.com/test/repo',
        branch: 'main',
        filesScanned: 0,
        filesSkipped: 0,
        vulnerabilities: [],
        severityCounts: { critical: 0, high: 0, medium: 0, low: 0, info: 0 },
        categoryCounts: {},
        hasBlockingIssues: false,
        scanDuration: 100,
        timestamp: '2024-01-15T10:00:00.000Z',
      }

      expect(existsSync(join(testDir, '.oculum'))).toBe(false)

      const result = manager.saveBaseline(scanResult)

      expect(result.success).toBe(true)
      expect(existsSync(join(testDir, '.oculum'))).toBe(true)
    })
  })

  describe('clearBaseline', () => {
    it('should return success with existed: false when no baseline exists', () => {
      const result = manager.clearBaseline()
      expect(result.success).toBe(true)
      expect(result.existed).toBe(false)
    })

    it('should delete existing baseline', () => {
      // Create baseline file
      mkdirSync(join(testDir, '.oculum'), { recursive: true })
      writeFileSync(join(testDir, '.oculum/baseline.json'), '{}')

      expect(existsSync(join(testDir, '.oculum/baseline.json'))).toBe(true)

      const result = manager.clearBaseline()

      expect(result.success).toBe(true)
      expect(result.existed).toBe(true)
      expect(existsSync(join(testDir, '.oculum/baseline.json'))).toBe(false)
    })
  })

  describe('hasBaseline', () => {
    it('should return false when no baseline exists', () => {
      expect(manager.hasBaseline()).toBe(false)
    })

    it('should return true when baseline exists', () => {
      mkdirSync(join(testDir, '.oculum'), { recursive: true })
      writeFileSync(join(testDir, '.oculum/baseline.json'), '{}')

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

  describe('getBaselinePath', () => {
    it('should return correct path', () => {
      expect(manager.getBaselinePath()).toBe(join(testDir, '.oculum/baseline.json'))
    })
  })
})
