/*
 * Copyright 2024 Signal Messenger, LLC
 * SPDX-License-Identifier: AGPL-3.0-only
 */

package org.thoughtcrime.video.app.transcode.composables

import android.net.Uri
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.material3.Checkbox
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Slider
import androidx.compose.material3.SliderDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import org.thoughtcrime.video.app.transcode.MAX_VIDEO_MEGABITRATE
import org.thoughtcrime.video.app.transcode.MIN_VIDEO_MEGABITRATE
import org.thoughtcrime.video.app.transcode.OPTIONS_AUDIO_KILOBITRATES
import org.thoughtcrime.video.app.transcode.TranscodeQuality
import org.thoughtcrime.video.app.transcode.TranscodeTestViewModel
import org.thoughtcrime.video.app.transcode.VideoResolution
import org.thoughtcrime.video.app.ui.composables.LabeledButton
import kotlin.math.roundToInt

/**
 * A view that shows the selected video URI and allows you to change the encoding options.
 */
@Composable
fun ConfigureEncodingParameters(
  onTranscodeClicked: () -> Unit,
  modifier: Modifier = Modifier,
  viewModel: TranscodeTestViewModel = viewModel()
) {
  Column(
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally,
    modifier = modifier
  ) {
    Text(
      text = "Selected video:",
      modifier = Modifier
        .padding(horizontal = 8.dp)
        .align(Alignment.Start)
    )
    viewModel.selectedVideo?.let {
      Text(
        text = it.toString(),
        fontSize = 8.sp,
        fontFamily = FontFamily.Monospace,
        modifier = Modifier
          .padding(horizontal = 8.dp)
          .align(Alignment.Start)
      )
    }
    Row(
      verticalAlignment = Alignment.CenterVertically,
      modifier = Modifier
        .fillMaxWidth()
    ) {
      Checkbox(
        checked = viewModel.useAutoTranscodingSettings,
        onCheckedChange = { viewModel.useAutoTranscodingSettings = it }
      )
      Text(
        text = "Match Signal App Transcoding Settings",
        style = MaterialTheme.typography.bodySmall
      )
    }
    if (viewModel.useAutoTranscodingSettings) {
      QualityPicker(
        viewModel.transcodeQuality,
        viewModel::updateTranscodeQuality,
        modifier = Modifier.padding(vertical = 16.dp)
      )
    } else {
      CustomSettings(
        selectedResolution = viewModel.videoResolution,
        onResolutionSelected = { viewModel.videoResolution = it },
        fastStartChecked = viewModel.enableFastStart,
        onFastStartSettingCheckChanged = { viewModel.enableFastStart = it },
        audioRemuxChecked = viewModel.enableAudioRemux,
        onAudioRemuxCheckChanged = { viewModel.enableAudioRemux = it },
        videoSliderPosition = viewModel.videoMegaBitrate,
        updateVideoSliderPosition = { viewModel.videoMegaBitrate = it },
        audioSliderPosition = viewModel.audioKiloBitrate,
        updateAudioSliderPosition = { viewModel.audioKiloBitrate = it.roundToInt() },
        modifier = Modifier.padding(vertical = 16.dp)
      )
    }
    LabeledButton(
      buttonLabel = "Transcode",
      onClick = onTranscodeClicked,
      modifier = Modifier.padding(vertical = 8.dp)
    )
  }
}

@Composable
internal fun QualityPicker(
  selectedTranscodeQuality: TranscodeQuality,
  onQualitySelected: (TranscodeQuality) -> Unit,
  modifier: Modifier = Modifier
) {
  Row(
    horizontalArrangement = Arrangement.SpaceEvenly,
    modifier = modifier
      .fillMaxWidth()
      .selectableGroup()
  ) {
    TranscodeQuality.entries.forEach {
      Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier
          .selectable(
            selected = selectedTranscodeQuality == it,
            onClick = {
              onQualitySelected(it)
            },
            role = Role.RadioButton
          )
      ) {
        RadioButton(
          selected = selectedTranscodeQuality == it,
          onClick = null,
          modifier = Modifier.semantics { contentDescription = it.name }
        )
        Text(
          text = it.name,
          textAlign = TextAlign.Center
        )
      }
    }
  }
}

@Composable
internal fun CustomSettings(
  selectedResolution: VideoResolution,
  onResolutionSelected: (VideoResolution) -> Unit,
  fastStartChecked: Boolean,
  onFastStartSettingCheckChanged: (Boolean) -> Unit,
  audioRemuxChecked: Boolean,
  onAudioRemuxCheckChanged: (Boolean) -> Unit,
  videoSliderPosition: Float,
  updateVideoSliderPosition: (Float) -> Unit,
  audioSliderPosition: Int,
  updateAudioSliderPosition: (Float) -> Unit,
  modifier: Modifier = Modifier
) {
  Row(
    horizontalArrangement = Arrangement.SpaceEvenly,
    modifier = modifier
      .fillMaxWidth()
      .selectableGroup()
  ) {
    VideoResolution.entries.forEach {
      Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier
          .selectable(
            selected = selectedResolution == it,
            onClick = { onResolutionSelected(it) },
            role = Role.RadioButton
          )
          .padding(start = 16.dp)
      ) {
        RadioButton(
          selected = selectedResolution == it,
          onClick = null,
          modifier = Modifier.semantics { contentDescription = it.getContentDescription() }
        )
        Text(
          text = "${it.shortEdge}p",
          textAlign = TextAlign.Center
        )
      }
    }
  }
  VideoBitrateSlider(videoSliderPosition, updateVideoSliderPosition)
  AudioBitrateSlider(audioSliderPosition, updateAudioSliderPosition)

  Row(
    verticalAlignment = Alignment.CenterVertically,
    modifier = Modifier
      .padding(vertical = 8.dp, horizontal = 8.dp)
      .fillMaxWidth()
  ) {
    Checkbox(
      checked = audioRemuxChecked,
      onCheckedChange = { onAudioRemuxCheckChanged(it) }
    )
    Text(text = "Allow audio remuxing", style = MaterialTheme.typography.bodySmall)
  }

  Row(
    verticalAlignment = Alignment.CenterVertically,
    modifier = Modifier
      .padding(vertical = 8.dp, horizontal = 8.dp)
      .fillMaxWidth()
  ) {
    Checkbox(
      checked = fastStartChecked,
      onCheckedChange = { onFastStartSettingCheckChanged(it) }
    )
    Text(text = "Perform Mp4San Postprocessing", style = MaterialTheme.typography.bodySmall)
  }
}

@Composable
private fun VideoBitrateSlider(
  videoSliderPosition: Float,
  updateSliderPosition: (Float) -> Unit,
  modifier: Modifier = Modifier
) {
  Slider(
    value = videoSliderPosition,
    onValueChange = updateSliderPosition,
    colors = SliderDefaults.colors(
      thumbColor = MaterialTheme.colorScheme.secondary,
      activeTrackColor = MaterialTheme.colorScheme.secondary,
      inactiveTrackColor = MaterialTheme.colorScheme.secondaryContainer
    ),
    valueRange = MIN_VIDEO_MEGABITRATE..MAX_VIDEO_MEGABITRATE,
    modifier = modifier.padding(top = 16.dp, start = 16.dp, end = 16.dp)
  )
  Text(text = String.format("Video: %.2f Mbit/s", videoSliderPosition))
}

@Composable
private fun AudioBitrateSlider(
  audioSliderPosition: Int,
  updateSliderPosition: (Float) -> Unit,
  modifier: Modifier = Modifier
) {
  val minValue = OPTIONS_AUDIO_KILOBITRATES.first().toFloat()
  val maxValue = OPTIONS_AUDIO_KILOBITRATES.last().toFloat()
  val steps = OPTIONS_AUDIO_KILOBITRATES.size - 2

  Slider(
    value = audioSliderPosition.toFloat(),
    onValueChange = updateSliderPosition,
    colors = SliderDefaults.colors(
      thumbColor = MaterialTheme.colorScheme.secondary,
      activeTrackColor = MaterialTheme.colorScheme.secondary,
      inactiveTrackColor = MaterialTheme.colorScheme.secondaryContainer
    ),
    valueRange = minValue..maxValue,
    steps = steps,
    modifier = modifier.padding(top = 16.dp, start = 16.dp, end = 16.dp)
  )
  Text(text = String.format("Audio: %d Kbit/s", audioSliderPosition))
}

@Preview(showBackground = true)
@Composable
private fun ConfigurationScreenPreviewPreset() {
  val vm: TranscodeTestViewModel = viewModel()
  vm.selectedVideo = Uri.parse("content://media/video/1")
  ConfigureEncodingParameters(onTranscodeClicked = {})
}

@Preview(showBackground = true)
@Composable
private fun ConfigurationScreenPreviewCustom() {
  val vm: TranscodeTestViewModel = viewModel()
  vm.selectedVideo = Uri.parse("content://media/video/1")
  vm.useAutoTranscodingSettings = false
  ConfigureEncodingParameters(onTranscodeClicked = {})
}
