// renderer.ts
import type { GameState, GameConfig, Bullet, Particle } from "./types"
import { createElement, random } from "./utils"

// Multi-layer canvas system for better performance
export class LayeredRenderer {
  private backgroundCanvas: HTMLCanvasElement | null = null
  private gameCanvas: HTMLCanvasElement | null = null
  private uiCanvas: HTMLCanvasElement | null = null

  private backgroundCtx: CanvasRenderingContext2D | null = null
  private gameCtx: CanvasRenderingContext2D | null = null
  private uiCtx: CanvasRenderingContext2D | null = null

  private CONFIG: GameConfig
  private uiElement: HTMLElement | null = null
  private uiNeedsUpdate: boolean = true

  constructor(config: GameConfig) {
    this.CONFIG = config

    if (typeof document === "undefined" || typeof window === "undefined") {
      return
    }

    this.initializeLayers()
  }

  private initializeLayers(): void {
    if (typeof document === "undefined") return

    // Background layer (static elements, rarely updated)
    this.backgroundCanvas = createElement("canvas") as HTMLCanvasElement
    this.setupCanvas(this.backgroundCanvas, 9999)
    this.backgroundCtx = this.backgroundCanvas.getContext("2d")

    // Game layer (dynamic game objects)
    this.gameCanvas = createElement("canvas") as HTMLCanvasElement
    this.setupCanvas(this.gameCanvas, 10000)
    this.gameCtx = this.gameCanvas.getContext("2d")

    // UI layer (HUD elements)
    this.uiCanvas = createElement("canvas") as HTMLCanvasElement
    this.setupCanvas(this.uiCanvas, 10001)
    this.uiCtx = this.uiCanvas.getContext("2d")

    // Add all canvases to DOM
    document.body.appendChild(this.backgroundCanvas)
    document.body.appendChild(this.gameCanvas)
    document.body.appendChild(this.uiCanvas)

    // Initialize UI element
    this.createUI()
  }

  private setupCanvas(canvas: HTMLCanvasElement, zIndex: number): void {
    canvas.width = this.CONFIG.canvas.width
    canvas.height = this.CONFIG.canvas.height

    Object.assign(canvas.style, {
      position: "fixed",
      top: "0",
      left: "0",
      zIndex: zIndex.toString(),
      background: "transparent",
      pointerEvents: "none",
    })
  }

  private createUI(): void {
    if (typeof document === "undefined") return

    this.uiElement = createElement("div")
    this.uiElement.id = "racleroids-ui"
    Object.assign(this.uiElement.style, {
      position: "fixed",
      top: "20px",
      left: "20px",
      color: "#DF944E",
      fontFamily: "Monaco, monospace",
      fontSize: "18px",
      zIndex: "10002",
      pointerEvents: "none",
    })
    document.body.appendChild(this.uiElement)
  }

  // Clear specific layers
  clearLayer(layer: "background" | "game" | "ui"): void {
    let ctx: CanvasRenderingContext2D | null = null

    switch (layer) {
      case "background":
        ctx = this.backgroundCtx
        break
      case "game":
        ctx = this.gameCtx
        break
      case "ui":
        ctx = this.uiCtx
        break
    }

    if (ctx) {
      ctx.clearRect(0, 0, this.CONFIG.canvas.width, this.CONFIG.canvas.height)
    }
  }

  // Render player on game layer
  drawPlayer(player: GameState["player"]): void {
    if (!this.gameCtx) return

    const ctx = this.gameCtx
    ctx.save()
    ctx.translate(player.position.x, player.position.y)
    ctx.rotate(player.direction)

    // Ship body - sleek triangle design
    ctx.strokeStyle = "#DF944E"
    ctx.lineWidth = 2
    ctx.beginPath()
    ctx.moveTo(this.CONFIG.player.size, 0)
    ctx.lineTo(-this.CONFIG.player.size * 0.7, -this.CONFIG.player.size * 0.5)
    ctx.lineTo(-this.CONFIG.player.size * 0.3, 0)
    ctx.lineTo(-this.CONFIG.player.size * 0.7, this.CONFIG.player.size * 0.5)
    ctx.closePath()
    ctx.stroke()

    // Ship core
    ctx.fillStyle = "#DF944E"
    ctx.beginPath()
    ctx.arc(0, 0, 3, 0, Math.PI * 2)
    ctx.fill()

    // Thrust flame
    if (player.thrust) {
      const flameLength = random(15, 25)
      ctx.strokeStyle = "#ff4000"
      ctx.lineWidth = 3
      ctx.beginPath()
      ctx.moveTo(-this.CONFIG.player.size * 0.3, 0)
      ctx.lineTo(-this.CONFIG.player.size - flameLength, random(-5, 5))
      ctx.stroke()

      ctx.strokeStyle = "#ffff00"
      ctx.lineWidth = 1
      ctx.beginPath()
      ctx.moveTo(-this.CONFIG.player.size * 0.3, 0)
      ctx.lineTo(-this.CONFIG.player.size - flameLength * 0.7, random(-3, 3))
      ctx.stroke()
    }

    ctx.restore()
  }

  // Batch render bullets for better performance
  drawBullets(bullets: Bullet[]): void {
    if (!this.gameCtx || bullets.length === 0) return

    const ctx = this.gameCtx
    ctx.fillStyle = "#00ffff"
    ctx.shadowColor = "#00ffff"
    ctx.shadowBlur = 5

    // Use path batching for better performance
    ctx.beginPath()
    for (let i = 0; i < bullets.length; i++) {
      const bullet = bullets[i]
      ctx.moveTo(
        bullet.position.x + this.CONFIG.bullets.size,
        bullet.position.y,
      )
      ctx.arc(
        bullet.position.x,
        bullet.position.y,
        this.CONFIG.bullets.size,
        0,
        Math.PI * 2,
      )
    }
    ctx.fill()

    ctx.shadowBlur = 0
  }

  // Batch render particles
  drawParticles(particles: Particle[]): void {
    if (!this.gameCtx || particles.length === 0) return

    const ctx = this.gameCtx
    ctx.lineCap = "round"

    // Group particles by color for batch rendering
    const particlesByColor = new Map<string, Particle[]>()

    for (let i = 0; i < particles.length; i++) {
      const particle = particles[i]
      const alpha = particle.life / particle.maxLife
      const colorWithAlpha =
        particle.color +
        Math.floor(alpha * 255)
          .toString(16)
          .padStart(2, "0")

      if (!particlesByColor.has(colorWithAlpha)) {
        particlesByColor.set(colorWithAlpha, [])
      }
      particlesByColor.get(colorWithAlpha)!.push(particle)
    }

    // Render each color group in batches
    particlesByColor.forEach((colorParticles, color) => {
      ctx.strokeStyle = color
      ctx.lineWidth = 2

      ctx.beginPath()
      for (let i = 0; i < colorParticles.length; i++) {
        const particle = colorParticles[i]
        const tail = {
          x: particle.velocity.x * -0.1,
          y: particle.velocity.y * -0.1,
        }

        ctx.moveTo(particle.position.x, particle.position.y)
        ctx.lineTo(particle.position.x + tail.x, particle.position.y + tail.y)
      }
      ctx.stroke()
    })
  }

  // Update UI layer (called less frequently)
  updateUI(
    score: number,
    enemies: number,
    totalEnemies: number,
    level: number,
  ): void {
    if (!this.uiElement || !this.uiNeedsUpdate) return

    this.uiElement.innerHTML = `
      <div>SCORE: ${score.toLocaleString()}</div>
      <div>TARGETS: ${enemies}/${totalEnemies}</div>
      <div>LEVEL: ${level}</div>
    `

    this.uiNeedsUpdate = false
  }

  // Mark UI for update (call when values change)
  markUIForUpdate(): void {
    this.uiNeedsUpdate = true
  }

  // Main render method
  render(state: GameState, bullets: Bullet[], particles: Particle[]): void {
    // Clear dynamic layers
    this.clearLayer("game")

    // Render game objects
    this.drawPlayer(state.player)
    this.drawBullets(bullets)
    this.drawParticles(particles)

    // Update UI if needed
    this.updateUI(
      state.score,
      state.enemies.length,
      state.totalEnemies,
      state.level,
    )
  }

  // Cleanup method
  cleanup(): void {
    if (this.backgroundCanvas) {
      this.backgroundCanvas.remove()
    }
    if (this.gameCanvas) {
      this.gameCanvas.remove()
    }
    if (this.uiCanvas) {
      this.uiCanvas.remove()
    }
    if (this.uiElement) {
      this.uiElement.remove()
      this.uiElement = null
    }
  }
}
