import type { Condition, Effect, ChoiceRecord } from '../types'

export class StateManager {
  variables: Record<string, number> = {}
  flags: Set<string> = new Set()
  history: ChoiceRecord[] = []
  onAfterApply: Set<((variables: Record<string, number>) => void)> = new Set()

  init(initialVars: Record<string, number>) {
    this.variables = { ...initialVars }
    this.flags = new Set()
    this.history = []
  }

  getVar(name: string): number {
    return this.variables[name] ?? 0
  }

  setVar(name: string, value: number) {
    this.variables[name] = value
  }

  addVar(name: string, delta: number) {
    this.variables[name] = (this.variables[name] ?? 0) + delta
  }

  hasFlag(name: string): boolean {
    return this.flags.has(name)
  }

  setFlag(name: string) {
    this.flags.add(name)
  }

  clearFlag(name: string) {
    this.flags.delete(name)
  }

  evaluate(conditions: Condition[]): boolean {
    return conditions.every((c) => {
      switch (c.op) {
        case '==':
          return this.variables[c.variable] === c.value
        case '!=':
          return this.variables[c.variable] !== c.value
        case '>':
          return (this.variables[c.variable] ?? 0) > (c.value as number)
        case '<':
          return (this.variables[c.variable] ?? 0) < (c.value as number)
        case '>=':
          return (this.variables[c.variable] ?? 0) >= (c.value as number)
        case '<=':
          return (this.variables[c.variable] ?? 0) <= (c.value as number)
        case 'hasFlag':
          return this.flags.has(c.variable)
        default:
          return false
      }
    })
  }

  apply(effects: Effect[]) {
    for (const e of effects) {
      switch (e.type) {
        case 'set':
          this.variables[e.target] = e.value as number
          break
        case 'add':
          this.addVar(e.target, e.value as number)
          break
        case 'toggleFlag':
          this.setFlag(e.target)
          break
      }
    }
    this.onAfterApply.forEach((cb) => cb(this.variables))
  }

  recordChoice(choice: ChoiceRecord) {
    this.history.push(choice)
  }

  toJSON() {
    return {
      variables: { ...this.variables },
      flags: [...this.flags],
      history: [...this.history],
    }
  }

  fromJSON(data: { variables: Record<string, number>; flags: string[]; history: ChoiceRecord[] }) {
    this.variables = { ...data.variables }
    this.flags = new Set(data.flags)
    this.history = [...data.history]
  }

  dump() {
    console.group('StateManager')
    console.table(this.variables)
    console.log('flags:', [...this.flags])
    console.table(this.history)
    console.groupEnd()
  }
}
