import './style.css'
import * as THREE from 'three'
import * as CANNON from 'cannon-es'
import type { PhysicsObject } from './types'
import { LightingManager } from './lighting'
import { ModelLoader } from './model-loader'
import { PhysicsManager } from './physics'
import { EventManager } from './event-manager'
import { PostProcessingManager } from './post-processing'

class AAFHomepage {
  private scene: THREE.Scene
  private camera: THREE.PerspectiveCamera
  private renderer: THREE.WebGLRenderer
  private world: CANNON.World
  private physicsObjects: PhysicsObject[] = []
  private mouse: THREE.Vector2
  private raycaster: THREE.Raycaster
  private attractionPoint: THREE.Vector3
  private mouseWorldPosition: THREE.Vector3
  private lastTime: number = 0
  private modelLoader: ModelLoader
  private eventManager: EventManager
  private postProcessing!: PostProcessingManager
  private usePostProcessing: boolean = true

  constructor() {
    this.scene = new THREE.Scene()
    this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000)
    
    const canvas = document.getElementById('three-canvas') as HTMLCanvasElement
    
    if (!canvas) {
      throw new Error('Canvas element not found')
    }
    
    this.renderer = new THREE.WebGLRenderer({ 
      canvas: canvas,
      antialias: true,
      alpha: true
    })
    this.world = PhysicsManager.setupPhysicsWorld()
    this.mouse = new THREE.Vector2()
    this.raycaster = new THREE.Raycaster()
    this.attractionPoint = new THREE.Vector3(0, 0, 0)
    this.mouseWorldPosition = new THREE.Vector3()
    this.modelLoader = new ModelLoader()

    // Initialize event manager
    this.eventManager = new EventManager(
      this.mouse,
      this.raycaster,
      this.mouseWorldPosition,
      this.camera,
      this.renderer
    )

    // Setup home button functionality
    this.setupHomeButton()

    // Initialize the scene
    this.init()
  }

  private setupHomeButton(): void {
    const homeButton = document.getElementById('home-button')
    if (homeButton) {
      homeButton.addEventListener('click', () => {
        window.location.href = 'https://home.aaf.systems/'
      })
    }
  }

  private init(): void {
    // Setup renderer
    this.renderer.setSize(window.innerWidth, window.innerHeight)
    this.renderer.setPixelRatio(window.devicePixelRatio)
    this.renderer.shadowMap.enabled = true
    this.renderer.shadowMap.type = THREE.PCFSoftShadowMap
    this.renderer.outputColorSpace = THREE.SRGBColorSpace
    this.renderer.toneMapping = THREE.ACESFilmicToneMapping
    this.renderer.toneMappingExposure = 1

    // Setup camera (moved closer to the action)
    this.camera.position.set(0, 0, 6)
    this.camera.lookAt(this.attractionPoint)

    // Setup lighting
    LightingManager.setupLighting(this.scene)

    // Initialize post-processing
    this.postProcessing = new PostProcessingManager(this.renderer, this.scene, this.camera)

    // Setup window resize handler
    window.addEventListener('resize', () => {
      const width = window.innerWidth
      const height = window.innerHeight
      
      this.camera.aspect = width / height
      this.camera.updateProjectionMatrix()
      
      this.renderer.setSize(width, height)
      this.postProcessing.resize(width, height)
    })

    // Load and create objects from the main model
    this.loadAndCreateObjects()

    // Setup event listeners
    this.eventManager.setupEventListeners()

    // Start animation loop
    this.animate()
  }

  private async loadAndCreateObjects(): Promise<void> {
    await this.modelLoader.loadAndCreateObjects(this.scene, this.world, this.physicsObjects)
  }

  private animate(currentTime: number = 0): void {
    requestAnimationFrame((time) => this.animate(time))

    // Calculate delta time
    const deltaTime = this.lastTime > 0 ? (currentTime - this.lastTime) / 1000 : 1/60
    this.lastTime = currentTime
    
    // Clamp delta time to prevent large jumps
    const clampedDeltaTime = Math.min(deltaTime, 1/30)

    PhysicsManager.updatePhysics(
      this.world,
      this.physicsObjects,
      this.attractionPoint,
      this.mouseWorldPosition,
      clampedDeltaTime
    )
    
    // Use post-processing rendering
    if (this.usePostProcessing) {
      this.postProcessing.update(clampedDeltaTime)
      this.postProcessing.render(clampedDeltaTime)
    } else {
      // Fallback to direct rendering
      this.renderer.render(this.scene, this.camera)
    }
  }
}

// Initialize the application
const app = new AAFHomepage()

export default app
