package tech.nut.nut_player_android

import android.content.Context
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import tech.nut.player.model.NutPlayer
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import tech.nut.player.model.HlsContent

/** Android platform implementation of the VideoPlayerPlugin.  */
class NutPlayerAndroidPlugin: FlutterPlugin, MethodChannel.MethodCallHandler, NutPlayerViewFactoryDelegate {

    private val players = emptyMap<Int, PlayerFlutterPlatform>().toMutableMap()
    private lateinit var pluginChannel: MethodChannel
    private lateinit var messenger: BinaryMessenger
    private lateinit var appContext: Context

    //constructor()

    override fun onAttachedToEngine(binding: FlutterPluginBinding) {

        appContext = binding.applicationContext
        messenger = binding.binaryMessenger

        pluginChannel = MethodChannel(
            messenger,
            "tech.nut/plugin"
        )

        pluginChannel.setMethodCallHandler(this)

        binding
            .platformViewRegistry
            .registerViewFactory("nut_player_view_id", NutPlayerViewFactory(this))
    }

    override fun onDetachedFromEngine(binding: FlutterPluginBinding) {
    }

    override fun onMethodCall(methodCall: MethodCall, result: MethodChannel.Result) {
        when (methodCall.method) {
            "pluginInitialize" -> {
                pluginInitialize(result)
            }

            "pluginCreate" -> {
                pluginCreate(methodCall, result)
            }

            "pluginDispose" -> {
                pluginDispose(methodCall, result)
            }

            "pluginPlay" -> {
                pluginPlay(methodCall, result)
            }

            "pluginPause" -> {
                pluginPause(methodCall, result)
            }

            "pluginGetVolume" -> {
                pluginGetVolume(methodCall, result)
            }

            "pluginSetVolume" -> {
                pluginSetVolume(methodCall, result)
            }

            "pluginSeek" -> {
                pluginSeek(methodCall, result)
            }

            "pluginSetPlaybackSpeed" -> {
                pluginSetPlaybackSpeed(methodCall, result)
            }

            "pluginGetPosition" -> {
                pluginGetPosition(methodCall, result)
            }

            else -> result.notImplemented()
        }
    }

    private fun pluginInitialize(result: MethodChannel.Result) {
        for (i in 0 until players.size) {
            players[i]?.nutPlayer?.release()
        }
        players.clear()
        result.success(null)
    }

    private fun pluginCreate(methodCall: MethodCall, result: MethodChannel.Result) {
        val args = methodCall.arguments as? ArrayList<*>
        val rawContent = args?.first() as? String
        val playerId = (1024..Int.MAX_VALUE - 2).random()
        val eventChannel = EventChannel(messenger,"tech.nut/videoPlayer/videoEvents/$playerId")

        rawContent?.let {
            val nutPlayer = PlayerFlutterPlatform(appContext, rawContent, eventChannel, pluginChannel)
            players[playerId] = nutPlayer
            result.success(playerId)
        } ?: run {
            result.notImplemented()
        }
    }

    private fun pluginDispose(methodCall: MethodCall, result: MethodChannel.Result) {
        val arguments = methodCall.arguments as? ArrayList<*>
        val playerId = arguments?.get(0)
        val player = players[playerId]

        if (playerId != null) {
            player?.dispose()
            players.remove(playerId)
        }

        result.success(null)
    }

    private fun pluginPlay(methodCall: MethodCall, result: MethodChannel.Result) {
        val arguments = methodCall.arguments as? ArrayList<*>
        val playerId = arguments?.get(0)

        if (playerId == null) {
            result.notImplemented()
            return
        }

        val player = players[playerId]
        player?.let {
            player.play()
            result.success(null)
        } ?: run {
            result.notImplemented()
        }
    }

    private fun pluginPause(methodCall: MethodCall, result: MethodChannel.Result) {
        val arguments = methodCall.arguments as? ArrayList<*>
        val playerId = arguments?.get(0)

        if (playerId == null) {
            result.notImplemented()
            return
        }

        val player = players[playerId]
        player?.let {
            player.pause()
            result.success(null)
        } ?: run {
            result.notImplemented()
        }
    }

    private fun pluginGetVolume(methodCall: MethodCall, result: MethodChannel.Result) {
        val arguments = methodCall.arguments as? ArrayList<*>
        val playerId = arguments?.get(0)

        if (playerId == null) {
            result.notImplemented()
            return
        }

        val player = players[playerId]
        player?.let {
            result.success(player.volume)
        } ?: run {
            result.notImplemented()
        }
    }

    private fun pluginSetVolume(methodCall: MethodCall, result: MethodChannel.Result) {
        val arguments = methodCall.arguments as? ArrayList<*>
        val playerId = arguments?.get(0)
        val volume = arguments?.get(1) as? Double

        if (playerId == null || volume == null) {
            result.notImplemented()
            return
        }

        val player = players[playerId]
        player?.let {
            player.setVolume(volume.toFloat())
            result.success(null)
        } ?: run {
            result.notImplemented()
        }
    }

    private fun pluginSetPlaybackSpeed(methodCall: MethodCall, result: MethodChannel.Result) {
        val arguments = methodCall.arguments as? ArrayList<*>
        val playerId = arguments?.get(0)
        val playbackSpeed = arguments?.get(1) as? Double

        if (playerId == null || playbackSpeed == null) {
            result.notImplemented()
            return
        }

        if (playbackSpeed !in 0.0..2.0) {
            result.notImplemented()
            return
        }

        val player = players[playerId]
        player?.let {
            player.setPlaybackSpeed(playbackSpeed)
            result.success(null)
        } ?: run {
            result.notImplemented()
        }
    }

    private fun pluginSeek(methodCall: MethodCall, result: MethodChannel.Result) {
        val arguments = methodCall.arguments as? ArrayList<*>
        val playerId = arguments?.get(0)
        val position = arguments?.get(1) as? Long

        if (playerId == null || position == null) {
            result.notImplemented()
            return
        }

        val player = players[playerId]
        player?.let {
            player.seek(position)
            result.success(null)
        } ?: run {
            result.notImplemented()
        }
    }

    private fun pluginGetPosition(methodCall: MethodCall, result: MethodChannel.Result) {
        val arguments = methodCall.arguments as? ArrayList<*>
        val playerId = arguments?.get(0)

        if (playerId == null) {
            result.notImplemented()
            return
        }

        val player = players[playerId]
        player?.let {
            result.success(player.position)
        } ?: run {
            result.notImplemented()
        }
    }

    // MARK: - NutPlayerViewFactoryDelegate

    override fun player(playerId: Int): NutPlayer? {
        return players[playerId]?.nutPlayer
    }

}