/**
 * SIM-10: Lieferketten-Renderer (SVG, 2D)
 *
 * Zeichnet eine vereinfachte Weltkarte als SVG, mit Markern für die
 * Baumwoll-Quellen, Nähereien und Wien. Wenn die Anwender*in eine Route
 * im Bestell-Formular zusammenstellt, wird sie hier als gestrichelte Linie
 * angezeigt — und beim Bestellen ein kleines Transport-Sprite (🚢/🚛/✈️)
 * über die Linie animiert.
 *
 * Das ist BEWUSST viel einfacher als der Klimawächter-3D-Renderer:
 *   - Keine Three.js, kein WebGL — nur SVG
 *   - Keine 60fps-Loop, nur Update bei Bedarf
 *   - Komplett pixel-flach, keine Schatten, kein Performance-Risiko
 */

import {
  COTTON_SOURCES,
  FACTORIES,
  TRANSPORT_MODES,
  VIENNA,
  type LieferkettenGame,
  type Order,
} from './game'

const SVG_NS = 'http://www.w3.org/2000/svg'

export class LieferkettenRenderer {
  private container: HTMLElement
  private game: LieferkettenGame
  private svg!: SVGSVGElement
  /** Aktuell im Bestell-Formular gewählte Route (für die Vorschau-Linie) */
  private previewOrder: Partial<Order> = {}
  private animationStart = 0
  private animatedSprites: Array<{ el: SVGTextElement; from: { x: number; y: number }; to: { x: number; y: number }; start: number; duration: number }> = []
  private rafId = 0

  constructor(container: HTMLElement, game: LieferkettenGame) {
    this.container = container
    this.game = game
  }

  start(): void {
    this.buildSVG()
    this.draw()
    this.tick()
  }

  stop(): void {
    if (this.rafId) cancelAnimationFrame(this.rafId)
    this.rafId = 0
  }

  /** Wird vom HTML aufgerufen, wenn der Spieler eine Bestell-Auswahl ändert */
  setPreviewOrder(order: Partial<Order>): void {
    this.previewOrder = { ...order }
    this.draw()
  }

  /** Wird beim Bestellen aufgerufen — animiert ein Sprite über die Route */
  animateOrder(order: Order): void {
    const cotton = COTTON_SOURCES.find(c => c.id === order.cottonId)
    const factory = FACTORIES.find(f => f.id === order.factoryId)
    const t1 = TRANSPORT_MODES.find(t => t.id === order.transport1)
    const t2 = TRANSPORT_MODES.find(t => t.id === order.transport2)
    if (!cotton || !factory || !t1 || !t2) return

    // Sprite 1: Baumwolle → Näherei
    const s1 = this.makeSprite(t1.emoji)
    this.animatedSprites.push({
      el: s1,
      from: cotton.pos,
      to: factory.pos,
      start: performance.now(),
      duration: 1500,
    })

    // Sprite 2: Näherei → Wien (startet etwas später)
    const s2 = this.makeSprite(t2.emoji)
    this.animatedSprites.push({
      el: s2,
      from: factory.pos,
      to: VIENNA,
      start: performance.now() + 800,
      duration: 1500,
    })
  }

  // ============================================================
  // Interna
  // ============================================================

  private buildSVG(): void {
    this.container.innerHTML = ''
    this.container.style.cssText = 'position:fixed;inset:0;background:linear-gradient(180deg,#dceaf0 0%,#bcd5e6 100%);'
    this.svg = document.createElementNS(SVG_NS, 'svg') as SVGSVGElement
    this.svg.setAttribute('viewBox', '0 0 100 60')
    this.svg.setAttribute('preserveAspectRatio', 'xMidYMid meet')
    this.svg.style.cssText = 'width:100%;height:100%;display:block;'
    this.container.appendChild(this.svg)
  }

  private draw(): void {
    if (!this.svg) return
    // Layers: Karte, Linien, Marker, Animation
    this.svg.innerHTML = `
      ${this.drawWorldShape()}
      ${this.drawRouteLines()}
      ${this.drawMarkers()}
    `
    // Animations-Sprites werden separat als DOM-Knoten gehalten
    for (const s of this.animatedSprites) {
      this.svg.appendChild(s.el)
    }
  }

  /**
   * Sehr stark vereinfachte Welt-Silhouette als <path>.
   * Wir zeichnen 4 grobe Kontinent-Blobs — keine Geo-Genauigkeit, nur damit
   * die Marker im richtigen Bereich sitzen.
   */
  private drawWorldShape(): string {
    const oceanGrad = `
      <defs>
        <linearGradient id="ocean" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" stop-color="#dceaf0" />
          <stop offset="100%" stop-color="#a0c0d0" />
        </linearGradient>
      </defs>
    `
    // Kontinent-Pfade — handgemalt, didaktische Vereinfachung
    const continents = `
      <!-- Nordamerika -->
      <path d="M 5,25 Q 8,20 14,22 Q 20,21 24,28 Q 26,38 22,46 Q 16,50 10,46 Q 4,40 5,25 Z"
            fill="#e8e3d4" stroke="#b0a890" stroke-width="0.2" />
      <!-- Südamerika -->
      <path d="M 20,48 Q 24,46 26,50 Q 28,55 24,58 Q 20,58 19,53 Z"
            fill="#e8e3d4" stroke="#b0a890" stroke-width="0.2" />
      <!-- Europa -->
      <path d="M 42,30 Q 48,28 52,32 Q 53,38 50,42 Q 44,42 42,38 Q 41,33 42,30 Z"
            fill="#e8e3d4" stroke="#b0a890" stroke-width="0.2" />
      <!-- Afrika -->
      <path d="M 46,42 Q 52,42 55,48 Q 56,55 50,57 Q 45,55 44,49 Q 44,44 46,42 Z"
            fill="#e8e3d4" stroke="#b0a890" stroke-width="0.2" />
      <!-- Asien (groß, diffus) -->
      <path d="M 53,28 Q 65,24 78,28 Q 86,32 84,42 Q 78,48 72,50 Q 60,48 56,42 Q 54,36 53,28 Z"
            fill="#e8e3d4" stroke="#b0a890" stroke-width="0.2" />
      <!-- Indien-Spitze -->
      <path d="M 65,46 Q 68,45 70,50 Q 67,53 64,51 Z"
            fill="#e8e3d4" stroke="#b0a890" stroke-width="0.2" />
      <!-- Australien -->
      <path d="M 80,52 Q 86,50 88,54 Q 86,57 81,56 Z"
            fill="#e8e3d4" stroke="#b0a890" stroke-width="0.2" />
    `
    return `${oceanGrad}<rect width="100" height="60" fill="url(#ocean)" />${continents}`
  }

  /** Zeichnet Routen-Linien:
   *   - dünne graue Linien für ALLE möglichen Verbindungen (zur Orientierung)
   *   - dicke gestrichelte Linie für die aktuell im Formular gewählte Route */
  private drawRouteLines(): string {
    let lines = ''
    // Vorschau-Route (wenn etwas gewählt ist)
    if (this.previewOrder.cottonId && this.previewOrder.factoryId) {
      const c = COTTON_SOURCES.find(s => s.id === this.previewOrder.cottonId)
      const f = FACTORIES.find(x => x.id === this.previewOrder.factoryId)
      if (c && f) {
        lines += this.line(c.pos, f.pos, '#c07a6b', 0.45)
      }
    }
    if (this.previewOrder.factoryId) {
      const f = FACTORIES.find(x => x.id === this.previewOrder.factoryId)
      if (f) {
        lines += this.line(f.pos, VIENNA, '#c07a6b', 0.45)
      }
    }
    return lines
  }

  private line(a: { x: number; y: number }, b: { x: number; y: number }, color: string, w: number): string {
    return `<line x1="${a.x}" y1="${a.y}" x2="${b.x}" y2="${b.y}"
      stroke="${color}" stroke-width="${w}" stroke-dasharray="1.2 0.8"
      stroke-linecap="round" />`
  }

  private drawMarkers(): string {
    let out = ''
    // Wien als rotes Ziel
    out += this.markerWithLabel(VIENNA.x, VIENNA.y, '🏛', 'Wien', '#b04a3a', 2.6)
    // Baumwoll-Quellen
    for (const c of COTTON_SOURCES) {
      const isSelected = this.previewOrder.cottonId === c.id
      out += this.markerWithLabel(
        c.pos.x, c.pos.y,
        c.flag, c.country,
        isSelected ? '#5a8a5e' : '#5a8a8a',
        isSelected ? 2.4 : 2.0,
      )
    }
    // Nähereien
    for (const f of FACTORIES) {
      const isSelected = this.previewOrder.factoryId === f.id
      // Position leicht versetzen, falls Factory am gleichen Ort wie Cotton
      const dx = (f.id === 'turkey-fab' && COTTON_SOURCES.some(c => c.id === 'turkey')) ? 1.5 : 0
      const dy = (f.id === 'turkey-fab' && COTTON_SOURCES.some(c => c.id === 'turkey')) ? 1.5 : 0
      out += this.markerWithLabel(
        f.pos.x + dx, f.pos.y + dy,
        f.emoji, f.country,
        isSelected ? '#5a8a5e' : '#7a6a5a',
        isSelected ? 2.4 : 2.0,
      )
    }
    return out
  }

  private markerWithLabel(x: number, y: number, emoji: string, label: string, color: string, size: number): string {
    return `
      <g>
        <circle cx="${x}" cy="${y}" r="${size}" fill="${color}" opacity="0.85" />
        <circle cx="${x}" cy="${y}" r="${size + 0.4}" fill="none" stroke="#fff" stroke-width="0.3" />
        <text x="${x}" y="${y + size * 0.45}" text-anchor="middle" font-size="${size * 1.4}">${emoji}</text>
        <text x="${x}" y="${y + size + 1.6}" text-anchor="middle" font-size="1.4"
              font-weight="700" fill="#1a1a1a"
              style="paint-order: stroke; stroke: #fff; stroke-width: 0.5;">${this.escape(label)}</text>
      </g>
    `
  }

  private makeSprite(emoji: string): SVGTextElement {
    const el = document.createElementNS(SVG_NS, 'text') as SVGTextElement
    el.setAttribute('font-size', '2.6')
    el.setAttribute('text-anchor', 'middle')
    el.textContent = emoji
    return el
  }

  private tick(): void {
    const now = performance.now()
    let stillRunning = false
    for (let i = this.animatedSprites.length - 1; i >= 0; i--) {
      const s = this.animatedSprites[i]
      const t = (now - s.start) / s.duration
      if (t < 0) {
        // noch nicht gestartet — verstecken
        s.el.setAttribute('x', '-100')
        s.el.setAttribute('y', '-100')
        stillRunning = true
        continue
      }
      if (t >= 1) {
        // Fertig — entfernen
        if (s.el.parentNode) s.el.parentNode.removeChild(s.el)
        this.animatedSprites.splice(i, 1)
        continue
      }
      // Linear interpolieren mit kleiner Hubbel
      const x = s.from.x + (s.to.x - s.from.x) * t
      const y = s.from.y + (s.to.y - s.from.y) * t - Math.sin(t * Math.PI) * 1.5
      s.el.setAttribute('x', String(x))
      s.el.setAttribute('y', String(y))
      stillRunning = true
    }
    // rAF-Loop
    this.rafId = requestAnimationFrame(() => this.tick())
  }

  private escape(s: string): string {
    return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
  }
}
