package de.duffy.screencast

import android.Manifest
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.media.projection.MediaProjectionManager
import android.os.Build
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import de.duffy.screencast.databinding.ActivityMainBinding

/**
 * Die ganze Bedienung: ein Knopf zum Starten, darunter die Adresse, die am
 * Fernseher eingetippt wird.
 */
class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    private val projectionRequest = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result.resultCode == RESULT_OK && result.data != null) {
            val intent = Intent(this, CastService::class.java).apply {
                action = CastService.ACTION_START
                putExtra(CastService.EXTRA_RESULT_CODE, result.resultCode)
                putExtra(CastService.EXTRA_RESULT_DATA, result.data)
                putExtra(CastService.EXTRA_QUALITY, selectedQuality())
                putExtra(CastService.EXTRA_FPS, selectedFps())
            }
            ContextCompat.startForegroundService(this, intent)
        } else {
            toast("Ohne Freigabe kann der Bildschirm nicht uebertragen werden")
        }
    }

    private val notificationRequest = registerForActivityResult(
        ActivityResultContracts.RequestPermission()
    ) { /* Ablehnung ist kein Beinbruch, der Dienst laeuft trotzdem */ }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.buttonToggle.setOnClickListener {
            if (CastState.running.value == true) stopCasting() else startCasting()
        }
        binding.buttonFindTv.setOnClickListener {
            startActivity(Intent(this, DeviceActivity::class.java))
        }
        binding.buttonCopy.setOnClickListener { copyUrl() }
        binding.textUrl.setOnClickListener { copyUrl() }

        observeState()
        askForNotificationPermission()
    }

    override fun onResume() {
        super.onResume()
        if (!NetworkUtil.isOnWifi(this) && CastState.running.value != true) {
            binding.textHint.text = getString(R.string.hint_no_wifi)
        } else {
            binding.textHint.text = getString(R.string.hint_ready)
        }
    }

    private fun observeState() {
        CastState.running.observe(this) { running ->
            binding.buttonToggle.text =
                getString(if (running) R.string.stop_casting else R.string.start_casting)
            binding.cardAddress.visibility =
                if (running && !CastState.url.value.isNullOrEmpty()) View.VISIBLE else View.GONE
            binding.groupSettings.visibility = if (running) View.GONE else View.VISIBLE
            binding.textHint.text = getString(
                if (running) R.string.hint_running else R.string.hint_ready
            )
        }
        CastState.url.observe(this) { url ->
            binding.textUrl.text = url
            binding.textUrlTs.text = if (url.isEmpty()) "" else "$url/stream.ts"
            binding.cardAddress.visibility =
                if (CastState.running.value == true && url.isNotEmpty()) View.VISIBLE else View.GONE
        }
        CastState.viewers.observe(this) { count ->
            binding.textViewers.text = resources.getQuantityString(R.plurals.viewers, count, count)
        }
        CastState.resolution.observe(this) { binding.textResolution.text = it }
        CastState.error.observe(this) { if (!it.isNullOrEmpty()) toast(it) }
    }

    private fun startCasting() {
        val manager = getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
        projectionRequest.launch(manager.createScreenCaptureIntent())
    }

    private fun stopCasting() {
        startService(Intent(this, CastService::class.java).setAction(CastService.ACTION_STOP))
    }

    private fun selectedQuality(): Int = when (binding.chipGroupQuality.checkedChipId) {
        R.id.chip_sd -> CastService.Quality.SD.ordinal
        R.id.chip_fhd -> CastService.Quality.FHD.ordinal
        else -> CastService.Quality.HD.ordinal
    }

    private fun selectedFps(): Int = if (binding.chipGroupFps.checkedChipId == R.id.chip_fps60) 60 else 30

    private fun copyUrl() {
        val url = CastState.url.value ?: return
        if (url.isEmpty()) return
        val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
        clipboard.setPrimaryClip(ClipData.newPlainText("Stream", url))
        toast("Adresse kopiert")
    }

    private fun askForNotificationPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
            checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED
        ) {
            notificationRequest.launch(Manifest.permission.POST_NOTIFICATIONS)
        }
    }

    private fun toast(text: String) = Toast.makeText(this, text, Toast.LENGTH_LONG).show()
}
