/**
 * Ported from backend/app/tests/test_mode_params.py — every pytest case
 * exists here with the same expected values, plus tests for
 * formatModeParams() (no Python counterpart: defined as the canonical
 * inverse of parseModeParams, matching the seed DSL strings).
 */
import { describe, expect, it } from 'vitest'
import { formatModeParams, parseModeParams } from '../../app/engine/modeParams'

describe('parseModeParams', () => {
  it('D30M50B.1G.2 => standard Licence G1 params', () => {
    const result = parseModeParams('D30M50B.1G.2')
    expect(result.duration_days).toBe(30)
    expect(result.majority_pct).toBe(50)
    expect(result.base_exponent).toBe(0.1)
    expect(result.gradient_exponent).toBe(0.2)
    // Optional criteria absent
    expect(result.smith_exponent).toBeNull()
    expect(result.techcomm_exponent).toBeNull()
  })

  it('D30M50B.1G.2S.1 => standard + smith_exponent=0.1', () => {
    const result = parseModeParams('D30M50B.1G.2S.1')
    expect(result.duration_days).toBe(30)
    expect(result.majority_pct).toBe(50)
    expect(result.base_exponent).toBe(0.1)
    expect(result.gradient_exponent).toBe(0.2)
    expect(result.smith_exponent).toBe(0.1)
    expect(result.techcomm_exponent).toBeNull()
  })

  it('D30M50B.1G.2T.1 => standard + techcomm_exponent=0.1', () => {
    const result = parseModeParams('D30M50B.1G.2T.1')
    expect(result.duration_days).toBe(30)
    expect(result.majority_pct).toBe(50)
    expect(result.base_exponent).toBe(0.1)
    expect(result.gradient_exponent).toBe(0.2)
    expect(result.smith_exponent).toBeNull()
    expect(result.techcomm_exponent).toBe(0.1)
  })

  it('D30M50B1G.5C10 => integer base, gradient=0.5, constant=10', () => {
    const result = parseModeParams('D30M50B1G.5C10')
    expect(result.duration_days).toBe(30)
    expect(result.majority_pct).toBe(50)
    expect(result.base_exponent).toBe(1.0)
    expect(result.gradient_exponent).toBe(0.5)
    expect(result.constant_base).toBe(10.0)
  })

  it('empty string returns all defaults', () => {
    const result = parseModeParams('')
    expect(result.duration_days).toBe(30)
    expect(result.majority_pct).toBe(50)
    expect(result.base_exponent).toBe(0.1)
    expect(result.gradient_exponent).toBe(0.2)
    expect(result.constant_base).toBe(0.0)
    expect(result.smith_exponent).toBeNull()
    expect(result.techcomm_exponent).toBeNull()
    expect(result.ratio_multiplier).toBeNull()
    expect(result.is_ratio_mode).toBe(false)
  })

  it('whitespace-only string treated as empty', () => {
    const result = parseModeParams('   ')
    expect(result.duration_days).toBe(30)
  })

  it('result exposes exactly the expected keys', () => {
    const result = parseModeParams('D30M50B.1G.2')
    const expectedKeys = [
      'duration_days',
      'majority_pct',
      'base_exponent',
      'gradient_exponent',
      'constant_base',
      'smith_exponent',
      'techcomm_exponent',
      'ratio_multiplier',
      'is_ratio_mode',
    ].sort()
    expect(Object.keys(result).sort()).toEqual(expectedKeys)
  })

  it('unknown code letter throws (Python parity)', () => {
    expect(() => parseModeParams('D30X5')).toThrow(/inconnu/)
  })

  it('D7R1N2.5 => ratio mode with multiplier (Python cross-check)', () => {
    const result = parseModeParams('D7R1N2.5')
    expect(result.duration_days).toBe(7)
    expect(result.is_ratio_mode).toBe(true)
    expect(result.ratio_multiplier).toBe(2.5)
    // Untouched defaults
    expect(result.majority_pct).toBe(50)
    expect(result.base_exponent).toBe(0.1)
    expect(result.gradient_exponent).toBe(0.2)
  })
})

describe('formatModeParams', () => {
  it('defaults format to the canonical standard string', () => {
    expect(formatModeParams()).toBe('D30M50B.1G.2')
    expect(formatModeParams({})).toBe('D30M50B.1G.2')
  })

  it('round-trips the seed DSL strings', () => {
    for (const s of ['D30M50B.1G.2', 'D30M50B.1G.2S.1', 'D30M50B.1G.2T.1']) {
      expect(formatModeParams(parseModeParams(s))).toBe(s)
    }
  })

  it('formats integer base and constant', () => {
    expect(formatModeParams(parseModeParams('D30M50B1G.5C10'))).toBe('D30M50B1G.5C10')
  })

  it('formats ratio mode and multiplier', () => {
    expect(formatModeParams(parseModeParams('D7R1N2.5'))).toBe('D7M50B.1G.2N2.5R1')
  })

  it('parse(format(p)) is identical to p', () => {
    for (const s of ['D30M50B.1G.2S.1', 'D30M50B1G.5C10', 'D7R1N2.5', 'D90M66B.2G.3S.2T.1']) {
      const p = parseModeParams(s)
      expect(parseModeParams(formatModeParams(p))).toEqual(p)
    }
  })
})
