/**
 * SIM-07: Erdbeben-Simulator — Canvas Renderer
 *
 * Visualisiert:
 * - Querschnitt der Erdkruste mit zwei tektonischen Platten
 * - Spannungsaufbau (visuell durch Risse/Verformung)
 * - Erdbeben-Welle bei Bruch
 * - Zwei Städte auf der Oberfläche (links arm, rechts reich)
 * - Schadensanzeige bei Beben
 *
 * Stil: Skandinavisch — gedeckte Erdfarben, klare Schichten
 */

import { ErdbebenSimulation, computeCityImpact, type QuakeEvent } from './logic'

interface SeismicWave {
  x: number
  y: number
  radius: number
  maxRadius: number
  intensity: number
}

interface DamageMarker {
  x: number
  y: number
  damage: number
  age: number
}

export class ErdbebenRenderer {
  private canvas: HTMLCanvasElement
  private ctx: CanvasRenderingContext2D
  private sim: ErdbebenSimulation
  private W = 0
  private H = 0
  private t = 0
  private animId = 0
  private waves: SeismicWave[] = []
  private damageA: DamageMarker[] = []
  private damageB: DamageMarker[] = []
  private shake = 0
  private autoTick = true
  private tickAccum = 0
  private lastQuake: QuakeEvent | null = null
  private lastImpact: ReturnType<ErdbebenSimulation['compareImpact']> | null = null

  // Layout (relative to H)
  private surfaceY = 0
  private mantleY = 0
  private cityAX = 0
  private cityBX = 0

  // Plate offsets (visual deformation)
  private plateLeftX = 0
  private plateRightX = 0

  private col = {
    sky:        '#dde3da',
    skyTop:     '#c8d4c6',
    crust:      '#a89878',
    crustDark:  '#8a7858',
    mantle:     '#c07a6b',
    mantleHot:  '#d08a7b',
    line:       '#5a5a5a',
    cityRich:   '#5a8a5e',
    cityPoor:   '#c4a35a',
    wave:       '#c07a6b',
    text:       '#1a1a1a',
    muted:      '#6a6a6a',
  }

  constructor(container: HTMLElement, sim: ErdbebenSimulation) {
    this.sim = sim
    this.canvas = document.createElement('canvas')
    this.canvas.style.cssText = 'width:100%;height:100%;display:block;border-radius:12px;'
    container.appendChild(this.canvas)
    const ctx = this.canvas.getContext('2d')
    if (!ctx) throw new Error('Canvas not supported')
    this.ctx = ctx

    this.resize()
    window.addEventListener('resize', () => this.resize())
  }

  private resize(): void {
    const rect = this.canvas.parentElement!.getBoundingClientRect()
    const dpr = window.devicePixelRatio || 1
    this.W = rect.width
    this.H = Math.min(rect.width * 0.65, 500)
    this.canvas.width = this.W * dpr
    this.canvas.height = this.H * dpr
    this.canvas.style.height = this.H + 'px'
    this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0)

    this.surfaceY = this.H * 0.45
    this.mantleY = this.H * 0.85
    this.cityAX = this.W * 0.25
    this.cityBX = this.W * 0.75
  }

  start(): void {
    const loop = () => {
      this.t += 0.016
      this.update()
      this.draw()
      this.animId = requestAnimationFrame(loop)
    }
    loop()
  }

  stop(): void {
    cancelAnimationFrame(this.animId)
  }

  triggerManualQuake(): void {
    // Force-tick until quake
    for (let i = 0; i < 200; i++) {
      const q = this.sim.tick()
      if (q) {
        this.spawnQuake(q)
        return
      }
    }
  }

  private update(): void {
    // Auto-tick
    if (this.autoTick) {
      this.tickAccum += 0.016
      if (this.tickAccum > 0.3) {  // Tick every 0.3s
        this.tickAccum = 0
        const q = this.sim.tick()
        if (q) this.spawnQuake(q)
      }
    }

    // Plate visual deformation based on stress
    const stress = this.sim.getStress()
    const targetOffset = Math.min(8, stress * 1.5)
    this.plateLeftX += (-targetOffset - this.plateLeftX) * 0.05
    this.plateRightX += (targetOffset - this.plateRightX) * 0.05

    // Update waves
    for (let i = this.waves.length - 1; i >= 0; i--) {
      const w = this.waves[i]
      w.radius += 4
      w.intensity *= 0.97
      if (w.radius > w.maxRadius) this.waves.splice(i, 1)
    }

    // Shake decay
    this.shake *= 0.92
  }

  private spawnQuake(q: QuakeEvent): void {
    this.lastQuake = q
    const epicenterX = q.epicenterX * this.W

    this.waves.push({
      x: epicenterX,
      y: this.surfaceY + 20,
      radius: 5,
      maxRadius: this.W * 0.8,
      intensity: 1,
    })

    this.shake = q.magnitude * 0.5

    // Reset plate visual deformation
    this.plateLeftX = 0
    this.plateRightX = 0

    // Compute city impacts
    this.lastImpact = this.sim.compareImpact(q.magnitude)

    // Add damage markers
    this.damageA.push({
      x: this.cityAX,
      y: this.surfaceY,
      damage: this.lastImpact.cityA.damage,
      age: 0,
    })
    this.damageB.push({
      x: this.cityBX,
      y: this.surfaceY,
      damage: this.lastImpact.cityB.damage,
      age: 0,
    })

    // Keep last 3 markers
    if (this.damageA.length > 3) this.damageA.shift()
    if (this.damageB.length > 3) this.damageB.shift()
  }

  private draw(): void {
    const { ctx, W, H } = this

    // Apply shake
    ctx.save()
    if (this.shake > 0.01) {
      ctx.translate((Math.random() - 0.5) * this.shake, (Math.random() - 0.5) * this.shake)
    }

    ctx.clearRect(-10, -10, W + 20, H + 20)

    // Sky
    const sky = ctx.createLinearGradient(0, 0, 0, this.surfaceY)
    sky.addColorStop(0, this.col.skyTop)
    sky.addColorStop(1, this.col.sky)
    ctx.fillStyle = sky
    ctx.fillRect(0, 0, W, this.surfaceY)

    // Sun
    ctx.fillStyle = '#e8c84a'
    ctx.beginPath()
    ctx.arc(W * 0.85, this.H * 0.12, 18, 0, Math.PI * 2)
    ctx.fill()

    // Earth crust (left plate)
    ctx.save()
    ctx.translate(this.plateLeftX, 0)
    ctx.fillStyle = this.col.crust
    ctx.fillRect(-20, this.surfaceY, W * 0.5 + 20, this.mantleY - this.surfaceY)
    ctx.fillStyle = this.col.crustDark
    ctx.fillRect(-20, this.mantleY - 8, W * 0.5 + 20, 8)
    // Surface texture
    ctx.fillStyle = this.col.crustDark
    for (let x = 0; x < W * 0.5; x += 25) {
      ctx.fillRect(x + 2, this.surfaceY, 1, 6 + Math.sin(x * 0.1) * 3)
    }
    ctx.restore()

    // Right plate
    ctx.save()
    ctx.translate(this.plateRightX, 0)
    ctx.fillStyle = this.col.crust
    ctx.fillRect(W * 0.5 - 5, this.surfaceY, W * 0.5 + 20, this.mantleY - this.surfaceY)
    ctx.fillStyle = this.col.crustDark
    ctx.fillRect(W * 0.5 - 5, this.mantleY - 8, W * 0.5 + 20, 8)
    for (let x = W * 0.5; x < W; x += 25) {
      ctx.fillRect(x + 2, this.surfaceY, 1, 6 + Math.sin(x * 0.1) * 3)
    }
    ctx.restore()

    // Plate boundary line (red, intensity = stress)
    const stress = this.sim.getStress()
    const boundaryAlpha = Math.min(0.8, stress * 0.15)
    ctx.strokeStyle = `rgba(192,80,60,${boundaryAlpha})`
    ctx.lineWidth = 2 + stress * 0.5
    ctx.beginPath()
    ctx.moveTo(W * 0.5, this.surfaceY)
    ctx.lineTo(W * 0.5, this.mantleY)
    ctx.stroke()

    // Mantle
    const mantleGrad = ctx.createLinearGradient(0, this.mantleY, 0, H)
    mantleGrad.addColorStop(0, this.col.mantle)
    mantleGrad.addColorStop(1, this.col.mantleHot)
    ctx.fillStyle = mantleGrad
    ctx.fillRect(0, this.mantleY, W, H - this.mantleY)

    // Magma blobs (animated)
    for (let i = 0; i < 5; i++) {
      const mx = (i / 5) * W + Math.sin(this.t + i) * 20
      const my = this.mantleY + 15 + Math.sin(this.t * 0.5 + i * 2) * 5
      ctx.fillStyle = `rgba(232,140,120,${0.3 + Math.sin(this.t + i) * 0.2})`
      ctx.beginPath()
      ctx.arc(mx, my, 8 + Math.sin(this.t * 2 + i) * 2, 0, Math.PI * 2)
      ctx.fill()
    }

    // Plate movement arrows
    if (stress > 0.5) {
      this.drawArrow(ctx, W * 0.15, this.mantleY - 25, 'right', stress * 0.3)
      this.drawArrow(ctx, W * 0.85, this.mantleY - 25, 'left', stress * 0.3)
    }

    // Cities
    this.drawCity(ctx, this.cityAX, this.surfaceY, 'rich', this.damageA[this.damageA.length - 1])
    this.drawCity(ctx, this.cityBX, this.surfaceY, 'poor', this.damageB[this.damageB.length - 1])

    // City labels
    ctx.fillStyle = this.col.text
    ctx.font = 'bold 11px Inter, sans-serif'
    ctx.textAlign = 'center'
    ctx.fillText('Stadt A', this.cityAX, this.surfaceY - 35)
    ctx.font = '9px Inter, sans-serif'
    ctx.fillStyle = this.col.muted
    ctx.fillText('(wohlhabend)', this.cityAX, this.surfaceY - 24)

    ctx.fillStyle = this.col.text
    ctx.font = 'bold 11px Inter, sans-serif'
    ctx.fillText('Stadt B', this.cityBX, this.surfaceY - 35)
    ctx.font = '9px Inter, sans-serif'
    ctx.fillStyle = this.col.muted
    ctx.fillText('(einkommensschwach)', this.cityBX, this.surfaceY - 24)

    // Seismic waves
    for (const w of this.waves) {
      ctx.strokeStyle = `rgba(192,122,107,${w.intensity * 0.7})`
      ctx.lineWidth = 2
      ctx.beginPath()
      ctx.arc(w.x, w.y, w.radius, 0, Math.PI * 2)
      ctx.stroke()

      // Inner waves
      ctx.lineWidth = 1
      ctx.strokeStyle = `rgba(192,122,107,${w.intensity * 0.4})`
      ctx.beginPath()
      ctx.arc(w.x, w.y, w.radius * 0.7, 0, Math.PI * 2)
      ctx.stroke()
    }

    ctx.restore()  // shake

    // ── Top info bar ──
    ctx.fillStyle = 'rgba(255,255,255,0.85)'
    ctx.fillRect(0, 0, W, 38)
    ctx.fillStyle = this.col.text
    ctx.font = 'bold 12px Inter, sans-serif'
    ctx.textAlign = 'left'
    ctx.fillText(`Spannung: ${stress.toFixed(1)}`, 12, 17)

    // Stress bar
    const barX = 105, barY = 8, barW = 80, barH = 8
    ctx.fillStyle = '#e0ddd6'
    ctx.beginPath()
    ctx.roundRect(barX, barY, barW, barH, 4)
    ctx.fill()
    const fillW = Math.min(barW, (stress / 5) * barW)
    ctx.fillStyle = stress > 4 ? '#c0503c' : stress > 2.5 ? '#c4a35a' : '#5a8a5e'
    ctx.beginPath()
    ctx.roundRect(barX, barY, fillW, barH, 4)
    ctx.fill()

    ctx.font = '11px Inter, sans-serif'
    ctx.fillStyle = this.col.muted
    ctx.fillText(`Beben: ${this.sim.getHistory().length}`, 200, 17)

    if (this.lastQuake) {
      ctx.fillStyle = this.col.text
      ctx.font = 'bold 11px Inter, sans-serif'
      ctx.fillText(`Letztes Beben: ${this.lastQuake.magnitude.toFixed(1)} M`, 280, 17)
    }

    // Bottom comparison panel (when impact computed)
    if (this.lastImpact) {
      const panelY = H - 60
      ctx.fillStyle = 'rgba(255,255,255,0.92)'
      ctx.fillRect(0, panelY, W, 60)

      // City A
      ctx.fillStyle = this.col.cityRich
      ctx.font = 'bold 11px Inter, sans-serif'
      ctx.textAlign = 'left'
      ctx.fillText(`Stadt A: ${this.lastImpact.cityA.damage}% Schaden`, 15, panelY + 20)
      ctx.fillStyle = this.col.muted
      ctx.font = '10px Inter, sans-serif'
      ctx.fillText(`${this.lastImpact.cityA.casualties} Opfer · Wiederaufbau: ${this.lastImpact.cityA.recovery}`, 15, panelY + 38)

      // City B
      ctx.fillStyle = this.col.cityPoor
      ctx.font = 'bold 11px Inter, sans-serif'
      ctx.textAlign = 'right'
      ctx.fillText(`Stadt B: ${this.lastImpact.cityB.damage}% Schaden`, W - 15, panelY + 20)
      ctx.fillStyle = this.col.muted
      ctx.font = '10px Inter, sans-serif'
      ctx.fillText(`${this.lastImpact.cityB.casualties} Opfer · Wiederaufbau: ${this.lastImpact.cityB.recovery}`, W - 15, panelY + 38)
    }
  }

  private drawArrow(ctx: CanvasRenderingContext2D, x: number, y: number, dir: 'left' | 'right', intensity: number): void {
    ctx.save()
    ctx.globalAlpha = Math.min(1, intensity)
    ctx.fillStyle = '#c0503c'
    ctx.strokeStyle = '#c0503c'
    ctx.lineWidth = 2

    const len = 25
    const sign = dir === 'right' ? 1 : -1
    ctx.beginPath()
    ctx.moveTo(x, y)
    ctx.lineTo(x + len * sign, y)
    ctx.stroke()
    // Arrow head
    ctx.beginPath()
    ctx.moveTo(x + len * sign, y)
    ctx.lineTo(x + (len - 6) * sign, y - 5)
    ctx.lineTo(x + (len - 6) * sign, y + 5)
    ctx.closePath()
    ctx.fill()
    ctx.restore()
  }

  private drawCity(ctx: CanvasRenderingContext2D, x: number, y: number, type: 'rich' | 'poor', damage?: DamageMarker): void {
    const dmg = damage ? damage.damage / 100 : 0
    const isRich = type === 'rich'

    if (isRich) {
      // Wohlhabende Stadt — moderne Hochhäuser
      const buildings = [
        { offX: -20, w: 8, h: 22 },
        { offX: -10, w: 10, h: 30 },
        { offX: 2, w: 12, h: 35 },
        { offX: 16, w: 8, h: 25 },
      ]
      for (const b of buildings) {
        const collapseRatio = Math.max(0, 1 - dmg * 0.6)
        const actualH = b.h * collapseRatio
        // Tilt if damaged
        const tilt = dmg * (Math.random() - 0.5) * 0.15
        ctx.save()
        ctx.translate(x + b.offX, y)
        ctx.rotate(tilt)
        ctx.fillStyle = dmg > 0.3 ? '#9a8a7a' : '#c0d0c8'
        ctx.fillRect(0, -actualH, b.w, actualH)
        // Windows
        if (dmg < 0.5) {
          ctx.fillStyle = '#5a8a8e'
          for (let wy = 4; wy < actualH - 2; wy += 6) {
            for (let wx = 1; wx < b.w - 2; wx += 4) {
              ctx.fillRect(wx, -actualH + wy, 2, 3)
            }
          }
        }
        ctx.restore()
      }
    } else {
      // Einkommensschwache Stadt — kleine, einfache Häuser
      const houses = [
        { offX: -22, w: 10, h: 12 },
        { offX: -10, w: 11, h: 14 },
        { offX: 2, w: 12, h: 13 },
        { offX: 15, w: 9, h: 10 },
        { offX: 25, w: 8, h: 11 },
      ]
      for (const h of houses) {
        const collapseRatio = Math.max(0.1, 1 - dmg * 0.95)
        const actualH = h.h * collapseRatio
        const tilt = dmg * (Math.random() - 0.5) * 0.4
        ctx.save()
        ctx.translate(x + h.offX, y)
        ctx.rotate(tilt)
        ctx.fillStyle = dmg > 0.4 ? '#8a7a6a' : '#d8c8a8'
        ctx.fillRect(0, -actualH, h.w, actualH)
        // Roof (only if not too damaged)
        if (dmg < 0.5) {
          ctx.fillStyle = '#a06050'
          ctx.beginPath()
          ctx.moveTo(-1, -actualH)
          ctx.lineTo(h.w / 2, -actualH - 4)
          ctx.lineTo(h.w + 1, -actualH)
          ctx.closePath()
          ctx.fill()
        }
        ctx.restore()

        // Rubble
        if (dmg > 0.3) {
          ctx.fillStyle = '#7a6a5a'
          ctx.fillRect(x + h.offX - 2, y - 2, h.w + 4, 2)
        }
      }
    }
  }
}
