// main.ts - OPTIMIZED VERSION WITH SINGLE ENEMY DETECTION
import type { GameState, GameConfig } from "./types"
import {
  createConfig,
  createVector,
  vectorOps,
  wrapPosition,
  createElement,
} from "./utils"
import { GameObjectManager } from "./gameObjects"
import { LayeredRenderer } from "./renderer"

// Global state tracking
let getsDeleted = false

// Main game class with performance optimizations
export class ModernAsteroids {
  private state: GameState | null = null
  private CONFIG: GameConfig = createConfig()
  private lastUpdate: number = 0
  private animationId: number = 0
  private keyDownHandler: ((e: KeyboardEvent) => void) | null = null
  private keyUpHandler: ((e: KeyboardEvent) => void) | null = null
  private styleElement: HTMLStyleElement | null = null

  // Performance optimized components
  private objectManager: GameObjectManager | null = null
  private renderer: LayeredRenderer | null = null

  // Performance tracking
  private frameCount: number = 0
  private lastFPSUpdate: number = 0
  private currentFPS: number = 0

  // PERFORMANCE: Frame timing analysis
  private isProfilingEnabled: boolean = false
  private performanceLog: Array<{ operation: string; time: number }> = []

  constructor() {
    // Early return if running on server
    if (typeof window === "undefined" || typeof document === "undefined") {
      console.warn("Racleroids game cannot initialize during SSR")
      return
    }

    // Update CONFIG with actual window dimensions now that we're in browser
    this.CONFIG = createConfig()
    getsDeleted = false

    try {
      this.initialize()
    } catch (error) {
      console.error("Failed to initialize Racleroids game:", error)
    }
  }

  private initialize(): void {
    if (typeof document === "undefined" || typeof window === "undefined") {
      return
    }

    // Initialize performance-optimized components
    this.objectManager = new GameObjectManager(this.CONFIG)
    this.renderer = new LayeredRenderer(this.CONFIG)

    // Initialize game state
    this.state = {
      player: {
        position: createVector(
          this.CONFIG.canvas.width / 2,
          this.CONFIG.canvas.height / 2,
        ),
        velocity: createVector(0, 0),
        direction: 0,
        thrust: false,
      },
      bullets: [], // This will be managed by objectManager
      particles: [], // This will be managed by objectManager
      enemies: [],
      totalEnemies: 0,
      score: 0,
      level: 1,
      keys: new Set(),
      lastFired: 0,
      isRunning: true,
    }

    // Initialize event handlers
    this.setupEventHandlers()
    this.setupStyles()
    const el = document.body
    if (el instanceof HTMLElement) {
      this.blinkElement(el)
    }
    this.bindEvents()
    // MODIFIED: Initial enemy detection - do this once at start and store result
    this.initializeEnemies()
    this.start()
  }

  private setupEventHandlers(): void {
    const keyMap: Record<string, string> = {
      ArrowUp: "up",
      ArrowDown: "down",
      ArrowLeft: "left",
      ArrowRight: "right",
      " ": "space",
      KeyB: "b",
      Escape: "escape",
      KeyP: "profile", // Add profiling toggle
    }

    this.keyDownHandler = (e: KeyboardEvent) => {
      if (!this.state) return
      const key = keyMap[e.code] || keyMap[e.key]
      if (key) {
        // Toggle profiling
        if (key === "profile" && !this.state.keys.has(key)) {
          this.isProfilingEnabled = !this.isProfilingEnabled
          console.log(
            `Performance profiling: ${this.isProfilingEnabled ? "ON" : "OFF"}`,
          )
        }

        this.state.keys.add(key)
        e.preventDefault()
      }
    }

    this.keyUpHandler = (e: KeyboardEvent) => {
      if (!this.state) return
      const key = keyMap[e.code] || keyMap[e.key]
      if (key) {
        this.state.keys.delete(key)
        e.preventDefault()
      }
    }
  }
  private blinkElement(element: Element | null): void {
    if (!(element instanceof HTMLElement)) return

    // Time markers for the blink
    const timings = [0, 500, 1000, 1500, 2000, 2500, 3000, 3500] // in ms

    timings.forEach((delay, index) => {
      setTimeout(() => {
        if (index % 2 === 0) {
          element.classList.add("asteroisBlink")
        } else {
          element.classList.remove("asteroisBlink")
        }
      }, delay)
    })
  }

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

    this.styleElement = createElement("style") as HTMLStyleElement
    this.styleElement.id = "racleroids-styles"
    this.styleElement.textContent = `    
      html,
      body.RACLEROIDS {
        cursor: none!important;
        overflow: hidden!important;
      }
      .asteroisBlink {
        border: 3px solid red!important;
        transition: border 0.3s ease-in-out;
      }
    `
    document.head.appendChild(this.styleElement)
    document.body.classList.add("RACLEROIDS")
  }

  private bindEvents(): void {
    if (
      typeof document === "undefined" ||
      !this.keyDownHandler ||
      !this.keyUpHandler
    ) {
      return
    }

    document.addEventListener("keydown", this.keyDownHandler)
    document.addEventListener("keyup", this.keyUpHandler)
  }

  // PERFORMANCE: Add timing wrapper for profiling
  private timeOperation<T>(name: string, operation: () => T): T {
    if (!this.isProfilingEnabled) {
      return operation()
    }

    const start = performance.now()
    const result = operation()
    const time = performance.now() - start

    this.performanceLog.push({ operation: name, time })

    return result
  }

  private handleInput(deltaTime: number): void {
    if (!this.state || !this.objectManager) return

    const { player, keys } = this.state

    player.thrust = keys.has("up")

    if (keys.has("up")) {
      const thrust = vectorOps.multiply(
        createVector(Math.cos(player.direction), Math.sin(player.direction)),
        this.CONFIG.player.acceleration * deltaTime,
      )
      player.velocity = vectorOps.add(player.velocity, thrust)

      // PERFORMANCE: Reduce thrust particle frequency
      if (Math.random() < 0.1) {
        // Reduced from 0.2
        const thrustPos = vectorOps.add(
          player.position,
          vectorOps.multiply(
            createVector(
              Math.cos(player.direction + Math.PI),
              Math.sin(player.direction + Math.PI),
            ),
            this.CONFIG.player.size,
          ),
        )
        this.objectManager.createParticlesAt(thrustPos, 1) // Reduced from 2
      }
    }

    if (keys.has("left")) {
      player.direction -= this.CONFIG.player.rotationSpeed * deltaTime
    }

    if (keys.has("right")) {
      player.direction += this.CONFIG.player.rotationSpeed * deltaTime
    }

    if (keys.has("space")) {
      this.fireBullet()
    }

    if (keys.has("escape")) {
      this.destroy()
    }

    // Apply drag
    player.velocity = vectorOps.multiply(player.velocity, 0.98)

    // Limit speed
    const speed = vectorOps.length(player.velocity)
    if (speed > this.CONFIG.player.maxSpeed) {
      player.velocity = vectorOps.setLength(
        player.velocity,
        this.CONFIG.player.maxSpeed,
      )
    }
  }

  private fireBullet(): void {
    if (!this.state || !this.objectManager) return

    const now = Date.now()
    if (now - this.state.lastFired < this.CONFIG.bullets.fireRate) return

    const bulletVelocity = vectorOps.add(
      vectorOps.multiply(
        createVector(
          Math.cos(this.state.player.direction),
          Math.sin(this.state.player.direction),
        ),
        this.CONFIG.bullets.speed,
      ),
      this.state.player.velocity,
    )

    const success = this.objectManager.createBulletAt(
      this.state.player.position,
      bulletVelocity,
    )

    if (success) {
      this.state.lastFired = now
    }
  }

  // MODIFIED: Initialize enemies once at game start
  private initializeEnemies(): void {
    if (!this.state || !this.objectManager) return

    this.state.enemies = this.timeOperation("enemies", () =>
      this.objectManager!.initializeEnemiesOnce(),
    )
    this.state.totalEnemies = this.state.enemies.length
  }

  private update(deltaTime: number): void {
    if (!this.state || !this.state.isRunning || !this.objectManager) return

    // Clear performance log for this frame
    if (this.isProfilingEnabled) {
      this.performanceLog = []
    }

    this.timeOperation("input", () => this.handleInput(deltaTime))

    // Update player position
    this.timeOperation("player", () => {
      this.state!.player.position = wrapPosition(
        vectorOps.add(
          this.state!.player.position,
          vectorOps.multiply(this.state!.player.velocity, deltaTime),
        ),
        this.CONFIG,
      )
    })

    // Update game objects using object manager
    this.timeOperation("bullets", () =>
      this.objectManager!.updateBullets(deltaTime),
    )

    this.timeOperation("particles", () =>
      this.objectManager!.updateParticles(deltaTime),
    )

    // REMOVED: No more periodic enemy updates - enemies are set once at start

    // Handle collisions using spatial grid
    const collision = this.timeOperation("collisions", () =>
      this.objectManager!.checkBulletCollisions(),
    )

    // PERFORMANCE: Batch DOM operations and defer non-critical ones
    if (collision.hitEnemies.length > 0) {
      let scoreChanged = false

      // Update score immediately (game critical)
      collision.hitEnemies.forEach(() => {
        this.state!.score += 10
        scoreChanged = true
      })

      // Defer DOM cleanup using requestIdleCallback for performance
      if ("requestIdleCallback" in window) {
        requestIdleCallback(
          () => {
            collision.hitEnemies.forEach((enemy) => {
              enemy.element.remove()
            })
          },
          { timeout: 100 },
        )
      } else {
        // Fallback: defer to next frame
        setTimeout(() => {
          collision.hitEnemies.forEach((enemy) => {
            enemy.element.remove()
          })
        }, 0)
      }

      // Update UI only when score changes
      if (scoreChanged && this.renderer) {
        this.renderer.markUIForUpdate()
      }
    }

    // Level progression
    const newLevel = Math.floor(this.state.score / 1000) + 1
    if (newLevel > this.state.level) {
      this.state.level = newLevel
      this.objectManager.createParticlesAt(this.state.player.position, 10) // Reduced from 20
      if (this.renderer) {
        this.renderer.markUIForUpdate()
      }
    }

    // PERFORMANCE: Update FPS less frequently
    if (this.frameCount % 6 === 0) {
      // Only every 6th frame instead of every 10th
      this.updateFPS()
    }

    // Log performance data if profiling is enabled
    if (this.isProfilingEnabled && this.performanceLog.length > 0) {
      const totalTime = this.performanceLog.reduce(
        (sum, log) => sum + log.time,
        0,
      )
      if (totalTime > 8) {
        // Only log frames taking more than 8ms
        console.log(
          `Frame time: ${totalTime.toFixed(1)}ms`,
          this.performanceLog
            .filter((log) => log.time > 1)
            .map((log) => `${log.operation}: ${log.time.toFixed(1)}ms`)
            .join(", "),
        )
      }
    }
  }

  private updateFPS(): void {
    this.frameCount++
    const now = performance.now()

    if (now - this.lastFPSUpdate >= 1000) {
      this.currentFPS = Math.round(
        (this.frameCount * 1000) / (now - this.lastFPSUpdate),
      )
      this.frameCount = 0
      this.lastFPSUpdate = now
    }
  }

  private render(): void {
    if (!this.renderer || !this.state || !this.objectManager) return

    // Get active objects from pools
    const bullets = this.objectManager.getActiveBullets()
    const particles = this.objectManager.getActiveParticles()

    // Render using layered renderer
    this.timeOperation("render", () =>
      this.renderer!.render(this.state!, bullets, particles),
    )
  }

  private gameLoop = (currentTime: number): void => {
    if (!this.state || !this.state.isRunning) return

    const frameStart = performance.now()

    const deltaTime = this.lastUpdate
      ? (currentTime - this.lastUpdate) / 1000
      : 0
    this.lastUpdate = currentTime

    // Cap delta time to prevent large jumps
    this.update(Math.min(deltaTime, 1 / 30))
    this.render()

    // PERFORMANCE: Log slow frames
    const frameTime = performance.now() - frameStart
    if (frameTime > 16.67 && this.isProfilingEnabled) {
      // More than 16.67ms = under 60fps
      console.warn(`Slow frame: ${frameTime.toFixed(1)}ms`)
    }

    if (this.state.isRunning) {
      this.animationId = requestAnimationFrame(this.gameLoop)
    }
  }

  private start(): void {
    if (typeof performance === "undefined" || !this.state) return

    this.lastUpdate = performance.now()
    this.lastFPSUpdate = this.lastUpdate
    this.gameLoop(this.lastUpdate)
  }

  public destroy(): void {
    getsDeleted = true

    if (this.state) {
      this.state.isRunning = false
    }

    if (this.animationId) {
      cancelAnimationFrame(this.animationId)
    }

    // Remove event listeners
    if (typeof document !== "undefined") {
      if (this.keyDownHandler) {
        document.removeEventListener("keydown", this.keyDownHandler)
      }
      if (this.keyUpHandler) {
        document.removeEventListener("keyup", this.keyUpHandler)
      }
    }

    // Cleanup optimized components
    if (this.objectManager) {
      this.objectManager.cleanup()
    }

    if (this.renderer) {
      this.renderer.cleanup()
    }

    // Remove styles
    if (this.styleElement) {
      this.styleElement.remove()
    }

    if (typeof document !== "undefined") {
      // Clean up enemy classes and restore body
      document.querySelectorAll(".RACLEROIDSENEMY").forEach((el) => {
        el.classList.remove("RACLEROIDSENEMY")
      })
      document.body.classList.remove("RACLEROIDS")
    }

    console.log("Racleroids game destroyed")
  }
}
function isTouchOnly() {
  const isTouchOnly =
    navigator.maxTouchPoints > 0 &&
    matchMedia("(pointer: coarse)").matches &&
    !matchMedia("(hover: hover)").matches
  return isTouchOnly
}
// Export function to create and start the game with SSR safety
export default (notifyUser): ModernAsteroids | null => {
  if (
    typeof window === "undefined" ||
    typeof document === "undefined" ||
    isTouchOnly()
  ) {
    console.warn("Racleroids game can only run in browser environment")
    return null
  }
  notifyUser()
  return new ModernAsteroids()
}
