package io.visus.orbis.feature.orb.service

import android.content.Context
import android.view.Surface
import io.visus.orbis.feature.orb.data.OrbRenderState
import kotlinx.coroutines.flow.StateFlow

/**
 * Service interface for rendering the orb using WebGPU.
 *
 * This service manages the complete lifecycle of WebGPU rendering, including GPU resource
 * initialization, surface management, and frame rendering. It exposes reactive state flows
 * for monitoring initialization status, errors, and performance metrics.
 *
 * Typical usage:
 * 1. Call [initialize] to set up WebGPU resources
 * 2. Call [attachSurface] when a rendering surface becomes available
 * 3. Call [startRenderLoop] to begin continuous rendering
 * 4. Update visual parameters via [updateRenderState]
 * 5. Call [stopRenderLoop] and [detachSurface] when the surface is no longer available
 * 6. Call [release] to clean up all GPU resources
 */
interface OrbRenderService {

    /**
     * Emits `true` when WebGPU initialization is complete and rendering is possible.
     */
    val isInitialized: StateFlow<Boolean>

    /**
     * Emits error messages when initialization or rendering fails, `null` otherwise.
     */
    val error: StateFlow<String?>

    /**
     * Emits the current frames per second, updated approximately once per second.
     */
    val fps: StateFlow<Int>

    /**
     * Initializes WebGPU resources including the GPU instance, adapter, device, shaders,
     * textures, and pipeline layouts.
     *
     * This must be called before any other rendering operations. The [isInitialized] flow
     * will emit `true` upon successful completion, or [error] will emit a message on failure.
     *
     * @param context Android context used to load shader and texture assets.
     */
    suspend fun initialize(context: Context)

    /**
     * Attaches a rendering surface and configures it for WebGPU output.
     *
     * This creates the GPU surface, configures its format and size, and builds the render
     * pipeline. Must be called after [initialize] and before [startRenderLoop].
     *
     * @param surface The Android [Surface] to render to.
     * @param width The surface width in pixels.
     * @param height The surface height in pixels.
     */
    suspend fun attachSurface(surface: Surface, width: Int, height: Int)

    /**
     * Detaches and releases the current rendering surface.
     *
     * This stops any active render loop and unconfigures the GPU surface. Call this when
     * the surface is destroyed or no longer available for rendering.
     */
    fun detachSurface()

    /**
     * Updates the render state parameters used for the next frame.
     *
     * @param state The new [OrbRenderState] containing color and amplitude values.
     */
    fun updateRenderState(state: OrbRenderState)

    /**
     * Renders a single frame to the attached surface.
     *
     * This updates uniforms, acquires a surface texture, executes the render pass,
     * and presents the result. Typically called automatically by the render loop,
     * but can be invoked manually for single-frame rendering.
     */
    fun render()

    /**
     * Starts the continuous render loop synchronized with the display refresh rate.
     *
     * Uses [android.view.Choreographer] to schedule frame callbacks, ensuring smooth
     * rendering aligned with VSync. The loop continues until [stopRenderLoop] is called.
     */
    fun startRenderLoop()

    /**
     * Stops the continuous render loop.
     *
     * Frame callbacks are removed and no further frames will be rendered automatically.
     */
    fun stopRenderLoop()

    /**
     * Releases all WebGPU resources and resets the service to an uninitialized state.
     *
     * This stops any active render loop and closes all GPU objects including the device,
     * adapter, textures, buffers, and pipelines. After calling this, [initialize] must
     * be called again before rendering.
     */
    fun release()
}
