package com.humand.demo.modules.AudioPlayer

import android.media.AudioAttributes
import android.media.MediaPlayer
import android.net.Uri
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.bridge.WritableMap
import java.io.File

class AudioPlayerModule(private val reactContext: ReactApplicationContext) :
    ReactContextBaseJavaModule(reactContext) {
    private var player: MediaPlayer? = null
    private var isPlaying: Boolean = false
    private var isPaused: Boolean = false
    private var playbackRate: Float = 1.0f

    // Controller for proximity sensor handling and audio output switching
    private val proximityController = ProximityController( reactContext)

    override fun getName() = "RNAudioPlayer"

    @ReactMethod
    fun replace(options: ReadableMap,  promise: Promise) {
        player?.reset()
        player?.release()
        player = null
        isPlaying = false
        isPaused = false

        val uriFromJs: String =
            if (options.hasKey("uri") && !options.isNull("uri"))
                options.getString("uri") ?: ""
            else ""

        if(uriFromJs.isBlank()){
            promise.reject(
                "HUMAND_AUDIO_PLAYER_ERROR",
                "No uri provided")
            return
        }

        val position =
            if (options.hasKey("position") && !options.isNull("position"))
                options.getDouble("position")
            else
               null

        val play =
            if (options.hasKey("play") && !options.isNull("play"))
                options.getBoolean("play")
            else
                false


        try {
            val uri = buildUri(uriFromJs)
            val mp = MediaPlayer()

            mp.setAudioAttributes(
                AudioAttributes.Builder()
                    .setUsage(AudioAttributes.USAGE_MEDIA)
                    .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                    .build()
            )

            mp.setDataSource(reactContext, uri)
            mp.setOnCompletionListener {
                proximityController.stop()
                isPlaying = false
                isPaused = false
                try {
                    val endPositionMs = player?.duration ?: 0
                    player?.seekTo(endPositionMs)
                } catch (_: Exception) {}
            }

            mp.prepare()
            player = mp

            if(position != null){
                seekTo(position)
            }

            if(play){
                proximityController.start()
                player?.start()
                isPlaying = true
                isPaused = false
            }

            val result = Arguments.createMap()
            result.putDouble("duration", getDurationSeconds())
            result.putString("uri", uriFromJs)
            promise.resolve(result)
        } catch (e: Exception) {
            promise.reject(
                "HUMAND_AUDIO_PLAYER_ERROR",
                "Failed to load audio file: ${e.message}",
                e
            )
        }
    }

    @ReactMethod
    fun play(promise: Promise) {
        val p = player ?: run { promise.resolve(null); return }
        if (!isPlaying) {
            proximityController.start()
            p.start()
            isPlaying = true
            isPaused = false
            applyPlaybackRate()
        }
        promise.resolve(null)
    }

    @ReactMethod
    fun pause(promise: Promise) {
        if (isPlaying) {
            val p = player ?: run { promise.resolve(null); return }
            isPaused = true
            isPlaying = false
            p.pause()
            proximityController.stop()
        }
        promise.resolve(null)
    }

    @ReactMethod
    fun seekTo(seconds: Double) {
        val p = player ?: return
        val durationMs = p.duration
        val targetMs = (seconds * 1000.0).toInt()

        if (targetMs < 0 || targetMs > durationMs) {
            return
        }

        p.seekTo(targetMs.toLong(), MediaPlayer.SEEK_CLOSEST)
    }

    @ReactMethod
    fun setPlaybackRate(rate: Double) {
        playbackRate = rate.toFloat()
        applyPlaybackRate()
    }

    @ReactMethod(isBlockingSynchronousMethod = true)
    fun getState(): WritableMap {
        val state: WritableMap = Arguments.createMap().apply {
            putBoolean("isPlaying", isPlaying)
            putBoolean("isPaused", isPaused)
            putDouble("duration", getDurationSeconds())
            putDouble("position", getCurrentTimeSeconds())
            putDouble("playbackRate", playbackRate.toDouble())
        }

        return state
    }

    @ReactMethod
    fun reset() {
        playbackRate = 1.0f
        isPlaying = false
        isPaused = false
        player?.reset()
        player?.release()
        player = null
        proximityController.stop()
    }

    private fun applyPlaybackRate() {
        val p = player ?: return
            try {
                val params = p.playbackParams
                params.speed = playbackRate
                p.playbackParams = params
            } catch (_: Exception) {
                //
            }
    }

    private fun getDurationSeconds(): Double {
        val ms = player?.duration ?: 0
        return ms.toDouble() / 1000.0
    }

    private fun getCurrentTimeSeconds(): Double {
        val ms = player?.currentPosition ?: 0
        return ms.toDouble() / 1000.0
    }

    private fun buildUri(path: String): Uri {
        return when {
            path.startsWith("file://") || path.startsWith("content://") ->
                Uri.parse(path)

            else ->
                Uri.fromFile(File(path))
        }
    }
}
