/**
 * Tests fuer SIM-12: Flussmanagement
 */
import { describe, it, expect } from 'vitest'
import {
  simulateRound, computeScore, computeCost, computeTotalCost,
  checkWinLose, checkFinalWin,
  LEVELS, CONTROL_META, STATE_META,
  type Controls, type State, type Conditions,
} from '../../src/sims/sim-12-fluss/logic'
import { FlussGame } from '../../src/sims/sim-12-fluss/game'

// Hilfsfunktion: Default-Zustand
function defaultState(): State {
  return {
    floodLocal: 50, floodDownstream: 40, erosion: 30,
    soilFertility: 60, biodiversity: 60, groundwater: 55,
    usableLand: 50, economy: 50,
  }
}

function emptyControls(): Controls {
  return {
    straightening: 0, levees: 0, dredging: 0,
    floodplainRelease: 0, renaturation: 0, irrigation: 0,
  }
}

function defaultConditions(): Conditions {
  return { rainfall: 60, extremeWeather: 30, slope: 40, populationPressure: 50, budget: 150 }
}

describe('Fluss-Simulation Logik', () => {

  describe('simulateRound', () => {
    it('gibt einen neuen State zurueck (Immutabilitaet)', () => {
      const state = defaultState()
      const result = simulateRound(state, emptyControls(), defaultConditions())
      expect(result).not.toBe(state) // Neues Objekt
    })

    it('ohne Massnahmen aendert sich wenig', () => {
      const state = defaultState()
      const result = simulateRound(state, emptyControls(), defaultConditions())
      // Werte sollten nah am Ausgangszustand sein
      for (const key of Object.keys(state) as (keyof State)[]) {
        expect(Math.abs(result[key] - state[key])).toBeLessThan(10)
      }
    })

    it('Deiche reduzieren lokales Hochwasser', () => {
      const state = defaultState()
      const controls = { ...emptyControls(), levees: 80 }
      const result = simulateRound(state, controls, defaultConditions())
      expect(result.floodLocal).toBeLessThan(state.floodLocal)
    })

    it('Begradigung erhoeht Hochwasser flussabwaerts', () => {
      const state = defaultState()
      const controls = { ...emptyControls(), straightening: 80 }
      const result = simulateRound(state, controls, defaultConditions())
      expect(result.floodDownstream).toBeGreaterThan(state.floodDownstream)
    })

    it('Renaturierung erhoeht Biodiversitaet', () => {
      const state = defaultState()
      const controls = { ...emptyControls(), renaturation: 70 }
      const result = simulateRound(state, controls, defaultConditions())
      expect(result.biodiversity).toBeGreaterThan(state.biodiversity)
    })

    it('Bewaesserung erhoeht Bodenfruchtbarkeit', () => {
      const state = defaultState()
      const controls = { ...emptyControls(), irrigation: 60 }
      const result = simulateRound(state, controls, defaultConditions())
      expect(result.soilFertility).toBeGreaterThan(state.soilFertility)
    })

    it('Auen freigeben reduziert Hochwasser lokal und flussabwaerts', () => {
      const state = defaultState()
      const controls = { ...emptyControls(), floodplainRelease: 70 }
      const result = simulateRound(state, controls, defaultConditions())
      expect(result.floodLocal).toBeLessThan(state.floodLocal)
      expect(result.floodDownstream).toBeLessThan(state.floodDownstream)
    })

    it('alle Werte bleiben zwischen 0 und 100', () => {
      // Extreme Kontrollen
      const controls: Controls = {
        straightening: 100, levees: 100, dredging: 100,
        floodplainRelease: 100, renaturation: 100, irrigation: 100,
      }
      const result = simulateRound(defaultState(), controls, defaultConditions())
      for (const key of Object.keys(result) as (keyof State)[]) {
        expect(result[key]).toBeGreaterThanOrEqual(0)
        expect(result[key]).toBeLessThanOrEqual(100)
      }
    })

    it('Hochwasser-Event erhoeht Floodwerte', () => {
      const state = defaultState()
      const event = { round: 1, type: 'flood_event' as const, intensity: 80 }
      const result = simulateRound(state, emptyControls(), defaultConditions(), event)
      expect(result.floodLocal).toBeGreaterThan(state.floodLocal)
    })

    it('Duerre-Event reduziert Grundwasser', () => {
      const state = defaultState()
      const event = { round: 1, type: 'drought' as const, intensity: 70 }
      const result = simulateRound(state, emptyControls(), defaultConditions(), event)
      expect(result.groundwater).toBeLessThan(state.groundwater)
    })
  })

  describe('computeScore', () => {
    it('berechnet alle Scores zwischen 0 und 100', () => {
      const score = computeScore(defaultState(), { safety: 0.25, ecology: 0.25, agriculture: 0.25, economy: 0.25 })
      expect(score.safety).toBeGreaterThanOrEqual(0)
      expect(score.safety).toBeLessThanOrEqual(100)
      expect(score.ecology).toBeGreaterThanOrEqual(0)
      expect(score.total).toBeGreaterThanOrEqual(0)
      expect(score.total).toBeLessThanOrEqual(100)
    })

    it('Gewichtung beeinflusst Gesamtscore', () => {
      const state: State = { ...defaultState(), economy: 90 }
      const scoreEco = computeScore(state, { safety: 0, ecology: 0, agriculture: 0, economy: 1 })
      const scoreSafe = computeScore(state, { safety: 1, ecology: 0, agriculture: 0, economy: 0 })
      expect(scoreEco.total).not.toEqual(scoreSafe.total)
    })
  })

  describe('computeCost', () => {
    it('0 Intensitaet kostet 0', () => {
      expect(computeCost('levees', 0)).toBe(0)
    })

    it('hoehere Intensitaet kostet mehr (ueberproportional)', () => {
      const cost50 = computeCost('levees', 50)
      const cost100 = computeCost('levees', 100)
      expect(cost100).toBeGreaterThan(cost50 * 1.5) // ueberproportional
    })
  })

  describe('Levels', () => {
    it('hat 5 Levels', () => {
      expect(LEVELS).toHaveLength(5)
    })

    it('jedes Level hat gueltige Struktur', () => {
      for (const l of LEVELS) {
        expect(l.id).toBeTruthy()
        expect(l.title).toBeTruthy()
        expect(l.rounds).toBeGreaterThan(0)
        expect(l.allowedControls.length).toBeGreaterThan(0)
        expect(l.conditions.budget).toBeGreaterThan(0)
      }
    })

    it('keine dominante Strategie: extreme Massnahme hat Nachteile', () => {
      // Teste ob maximale Begradigung nicht alles verbessert
      const state = LEVELS[3].initialState // Level 4 (Gleichgewicht)
      const conditions = LEVELS[3].conditions
      const extremeControls = { ...emptyControls(), straightening: 100 }
      const result = simulateRound({ ...state }, extremeControls, conditions)

      // Begradigung muss MINDESTENS einen Nachteil haben
      const hasDownside =
        result.biodiversity < state.biodiversity ||
        result.floodDownstream > state.floodDownstream ||
        result.groundwater < state.groundwater ||
        result.erosion > state.erosion
      expect(hasDownside).toBe(true)
    })
  })

  describe('CONTROL_META / STATE_META', () => {
    it('hat Metadaten fuer alle 6 Massnahmen', () => {
      expect(Object.keys(CONTROL_META)).toHaveLength(6)
    })

    it('hat Metadaten fuer alle 8 Zustandsparameter', () => {
      expect(Object.keys(STATE_META)).toHaveLength(8)
    })
  })
})

describe('FlussGame', () => {
  it('startet mit level-select Phase', () => {
    const game = new FlussGame()
    expect(game.phase).toBe('level-select')
  })

  it('selectLevel setzt korrekt auf', () => {
    const game = new FlussGame()
    game.selectLevel('L1')
    expect(game.level.id).toBe('L1')
    expect(game.phase).toBe('intro')
    expect(game.round).toBe(0)
    expect(game.budgetRemaining).toBe(120) // L1 budget
  })

  it('serialize / deserialize roundtrip', () => {
    const game = new FlussGame()
    game.selectLevel('L2')
    game.startPlaying()
    game.setControl('levees', 40)
    game.executeRound()

    const json = game.serialize()
    const game2 = new FlussGame()
    expect(game2.deserialize(json)).toBe(true)
    expect(game2.level.id).toBe('L2')
    expect(game2.round).toBe(1)
  })
})
