/**
 * Unity WebGL Bridge
 * Communication layer between React and Unity WebGL
 */

import { LearningNode, AOIManifest } from '@/app/geo-lernwelt/types'

// Message types from Unity to React
export type UnityMessageType =
  | 'nodeSelected'
  | 'terrainLoaded'
  | 'cameraPosition'
  | 'error'
  | 'ready'
  | 'progress'

export interface UnityMessage {
  type: UnityMessageType
  nodeId?: string
  position?: { x: number; y: number; z: number }
  message?: string
  progress?: number
}

// Message handler type
export type UnityMessageHandler = (message: UnityMessage) => void

// Unity instance interface
export interface UnityInstance {
  SendMessage: (objectName: string, methodName: string, value?: string | number) => void
  Quit: () => Promise<void>
}

// Unity loader configuration
export interface UnityLoaderConfig {
  dataUrl: string
  frameworkUrl: string
  codeUrl: string
  streamingAssetsUrl: string
  companyName: string
  productName: string
  productVersion: string
}

/**
 * Unity Bridge class for managing communication
 */
export class UnityBridge {
  private instance: UnityInstance | null = null
  private messageHandlers: UnityMessageHandler[] = []
  private isReady: boolean = false

  constructor() {
    // Set up global message handler
    if (typeof window !== 'undefined') {
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      (window as any).handleUnityMessage = this.handleMessage.bind(this)
    }
  }

  /**
   * Set the Unity instance (called after Unity loads)
   */
  setInstance(instance: UnityInstance) {
    this.instance = instance
    this.isReady = true
  }

  /**
   * Check if Unity is ready
   */
  ready(): boolean {
    return this.isReady && this.instance !== null
  }

  /**
   * Register a message handler
   */
  onMessage(handler: UnityMessageHandler): () => void {
    this.messageHandlers.push(handler)

    // Return unsubscribe function
    return () => {
      const index = this.messageHandlers.indexOf(handler)
      if (index > -1) {
        this.messageHandlers.splice(index, 1)
      }
    }
  }

  /**
   * Handle incoming message from Unity
   */
  private handleMessage(messageJson: string) {
    try {
      const message: UnityMessage = JSON.parse(messageJson)

      // Notify all handlers
      this.messageHandlers.forEach((handler) => {
        try {
          handler(message)
        } catch (e) {
          console.error('Error in Unity message handler:', e)
        }
      })
    } catch (e) {
      console.error('Failed to parse Unity message:', e)
    }
  }

  /**
   * Send a message to Unity
   */
  sendMessage(objectName: string, methodName: string, value?: string | number) {
    if (!this.instance) {
      console.warn('Unity instance not ready, message queued')
      return false
    }

    try {
      this.instance.SendMessage(objectName, methodName, value)
      return true
    } catch (e) {
      console.error('Error sending message to Unity:', e)
      return false
    }
  }

  // ============================================
  // Terrain Commands
  // ============================================

  /**
   * Load terrain from manifest
   */
  loadTerrain(manifestUrl: string) {
    return this.sendMessage('TerrainManager', 'LoadManifest', manifestUrl)
  }

  /**
   * Set terrain exaggeration (vertical scale)
   */
  setTerrainExaggeration(exaggeration: number) {
    return this.sendMessage('TerrainManager', 'SetExaggeration', exaggeration)
  }

  /**
   * Toggle terrain wireframe mode
   */
  toggleWireframe(enabled: boolean) {
    return this.sendMessage('TerrainManager', 'SetWireframe', enabled ? 1 : 0)
  }

  // ============================================
  // Camera Commands
  // ============================================

  /**
   * Focus camera on a learning node
   */
  focusOnNode(nodeId: string) {
    return this.sendMessage('CameraController', 'FocusOnNode', nodeId)
  }

  /**
   * Focus camera on a position
   */
  focusOnPosition(x: number, y: number, z: number) {
    return this.sendMessage(
      'CameraController',
      'FocusOnPosition',
      JSON.stringify({ x, y, z })
    )
  }

  /**
   * Set camera mode
   */
  setCameraMode(mode: 'orbit' | 'fly' | 'firstPerson') {
    return this.sendMessage('CameraController', 'SetMode', mode)
  }

  /**
   * Reset camera to default view
   */
  resetCamera() {
    return this.sendMessage('CameraController', 'Reset')
  }

  // ============================================
  // Learning Node Commands
  // ============================================

  /**
   * Load learning nodes
   */
  loadNodes(nodes: LearningNode[]) {
    return this.sendMessage(
      'LearningNodeManager',
      'LoadNodes',
      JSON.stringify(nodes)
    )
  }

  /**
   * Add a single learning node
   */
  addNode(node: LearningNode) {
    return this.sendMessage(
      'LearningNodeManager',
      'AddNode',
      JSON.stringify(node)
    )
  }

  /**
   * Remove a learning node
   */
  removeNode(nodeId: string) {
    return this.sendMessage('LearningNodeManager', 'RemoveNode', nodeId)
  }

  /**
   * Update a learning node
   */
  updateNode(node: LearningNode) {
    return this.sendMessage(
      'LearningNodeManager',
      'UpdateNode',
      JSON.stringify(node)
    )
  }

  /**
   * Highlight a learning node
   */
  highlightNode(nodeId: string, highlight: boolean) {
    return this.sendMessage(
      'LearningNodeManager',
      'HighlightNode',
      JSON.stringify({ nodeId, highlight })
    )
  }

  /**
   * Show/hide all nodes
   */
  setNodesVisible(visible: boolean) {
    return this.sendMessage('LearningNodeManager', 'SetVisible', visible ? 1 : 0)
  }

  // ============================================
  // UI Commands
  // ============================================

  /**
   * Toggle UI visibility
   */
  toggleUI(visible: boolean) {
    return this.sendMessage('UIManager', 'SetVisible', visible ? 1 : 0)
  }

  /**
   * Show toast message
   */
  showToast(message: string) {
    return this.sendMessage('UIManager', 'ShowToast', message)
  }

  /**
   * Set language
   */
  setLanguage(lang: 'de' | 'en') {
    return this.sendMessage('UIManager', 'SetLanguage', lang)
  }

  // ============================================
  // Screenshot & Recording
  // ============================================

  /**
   * Take a screenshot
   */
  takeScreenshot(): Promise<string> {
    return new Promise((resolve, reject) => {
      const handler = (message: UnityMessage) => {
        if (message.type === 'error') {
          reject(new Error(message.message))
          return true
        }
        // Would need custom message type for screenshot result
        return false
      }

      const unsubscribe = this.onMessage(handler)
      this.sendMessage('ScreenshotManager', 'TakeScreenshot')

      // Timeout after 5 seconds
      setTimeout(() => {
        unsubscribe()
        reject(new Error('Screenshot timeout'))
      }, 5000)
    })
  }

  // ============================================
  // Lifecycle
  // ============================================

  /**
   * Quit Unity
   */
  async quit() {
    if (this.instance) {
      await this.instance.Quit()
      this.instance = null
      this.isReady = false
    }
  }

  /**
   * Cleanup
   */
  destroy() {
    this.messageHandlers = []
    if (typeof window !== 'undefined') {
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      delete (window as any).handleUnityMessage
    }
  }
}

// Singleton instance
let bridgeInstance: UnityBridge | null = null

/**
 * Get or create the Unity bridge instance
 */
export function getUnityBridge(): UnityBridge {
  if (!bridgeInstance) {
    bridgeInstance = new UnityBridge()
  }
  return bridgeInstance
}

/**
 * Create Unity loader configuration
 */
export function createLoaderConfig(buildPath: string): UnityLoaderConfig {
  return {
    dataUrl: `${buildPath}/WebGL.data`,
    frameworkUrl: `${buildPath}/WebGL.framework.js`,
    codeUrl: `${buildPath}/WebGL.wasm`,
    streamingAssetsUrl: `${buildPath}/StreamingAssets`,
    companyName: 'BreakPilot',
    productName: 'GeoEdu Lernwelt',
    productVersion: '1.0.0',
  }
}
