package ffmpeg

import data.AudioAdjustmentData
import data.CommandRunnerImp
import data.FileUtilitiesDefault
import data.Message
import ffprobe.FfprobeMkvToMp4
import ffprobe.FfprobeStreams
import interfaces.AudioAdjustment
import interfaces.CommandRunner
import interfaces.FileUtilities
import interfaces.MkvToMp4
import interfaces.Streams
import ui.JOptionPaneUserNotifier
import ui.interfaces.UserNotifier
import java.io.File
import java.util.ResourceBundle
import java.util.logging.Logger

class FfmpegAudioAdjustment(
    private val userNotifier: UserNotifier = JOptionPaneUserNotifier(),
    private val messages: ResourceBundle = Message().messages,
    private val stream: Streams = FfprobeStreams(),
    private val commandRunner: CommandRunner = CommandRunnerImp(),
    private val mkvToMp4: MkvToMp4 = FfprobeMkvToMp4(),
    private val fileUtilities: FileUtilities = FileUtilitiesDefault(),
) : AudioAdjustment {
    private val logger = Logger.getLogger(this.javaClass.name)

    override fun audioAdjustment(file: File) {
        var tempFile = file

        if (stream.getUnsupportedAudioStreams(file).isNotEmpty()) {
            tempFile = mkvToMp4.convertToMp4(file)
        }

        val allStreams = stream.getAudioStreams(tempFile)

        if (allStreams.isEmpty()) {
            userNotifier.showError(messages.getString("nenhum_fluxo_de_audio"))
            return
        }

        val adjustmentData: AudioAdjustmentData? = userNotifier.adjustAudioStreams(allStreams)

        if (adjustmentData == null) {
            logger.info("User canceled the audio adjustment.")
            return
        }

        val (selectedStreams, adjustmentValue, isAdvance) = adjustmentData

        if (selectedStreams.isEmpty()) {
            userNotifier.showWarning(messages.getString("nenhum_audio_selecionado"))
            return
        }

        executeAdjustment(stream, selectedStreams, adjustmentValue, isAdvance, tempFile)
    }

    private fun executeAdjustment(
        stream: Streams,
        selectedStreams: List<Map<String, String>>,
        adjustmentValue: Double,
        isAdvance: Boolean,
        file: File,
    ) {
        val selectedStreamIndexes = selectedStreams.map { it["index"] ?: "" }
        if (selectedStreamIndexes.isEmpty()) {
            logger.warning("No audio stream selected for adjustment.")
            return
        }

        val inputFile = file.absolutePath
        val outputFile = fileUtilities.generateUniqueFileName(file).absolutePath

        val itsoffsetValue = if (isAdvance) -adjustmentValue else adjustmentValue

        val command = mutableListOf<String>()
        command.add("ffmpeg")
        command.add("-copyts")
        command.add("-i")
        command.add(inputFile)
        command.add("-itsoffset")
        command.add(itsoffsetValue.toString())
        command.add("-i")
        command.add(inputFile)

        val videoStreams = stream.getVideoStream(file)

        videoStreams.onEachIndexed { index, _ ->
            command.add("-map")
            command.add("0:$index")
        }

        val audioStreams = stream.getAudioStreams(file)
        val allAudioStreamIndexes = audioStreams.map { it["index"] ?: "" }

        val nonAdjustedIndexes = allAudioStreamIndexes.filter { !selectedStreamIndexes.contains(it) }
        nonAdjustedIndexes.forEach { index ->
            command.add("-map")
            command.add("0:$index")
        }

        selectedStreamIndexes.forEach { index ->
            command.add("-map")
            command.add("1:$index")
        }

        command.add("-c")
        command.add("copy")

        command.add("-map_metadata")
        command.add("0")

        command.add("-avoid_negative_ts")
        command.add("make_zero")

        command.add(outputFile)

        commandRunner.runCommand(
            command.toTypedArray(),
            stream.getDuration(file)
        )
    }
}

INFORMAÇÕES: command: ffmpeg -copyts -i C:\Users\xiyun\Downloads\[ACESSE...HD-ELITE.ME]...Paprika.2006.BluRay.1080p.x264.DTS.5.1.Dual\Paprika.2006.BluRay.1080p.x264.DTS.5.1.Dual\Paprika.2006.BluRay.1080p.x264.DTS.5.1.Dual part 0.mp4 -itsoffset 5.0 -i C:\Users\xiyun\Downloads\[ACESSE...HD-ELITE.ME]...Paprika.2006.BluRay.1080p.x264.DTS.5.1.Dual\Paprika.2006.BluRay.1080p.x264.DTS.5.1.Dual\Paprika.2006.BluRay.1080p.x264.DTS.5.1.Dual part 0.mp4 -map 0:0 -map 0:1 -map 0:2 -map 0:3 -map 0:4 -map 0:5 -map 0:6 -map 0:7 -map 0:8 -map 0:9 -map 0:10 -map 0:11 -map 0:12 -map 0:13 -map 0:14 -map 0:15 -map 0:16 -map 0:17 -map 0:18 -map 0:19 -map 0:20 -map 0:21 -map 0:22 -map 0:23 -map 0:24 -map 0:25 -map 0:26 -map 0:27 -map 0:28 -map 0:29 -map 0:30 -map 0:31 -map 0:32 -map 0:33 -map 0:34 -map 0:35 -map 0:36 -map 0:37 -map 0:38 -map 0:39 -map 0:40 -map 0:41 -map 0:42 -map 0:43 -map 0:44 -map 0:45 -map 0:46 -map 0:47 -map 0:48 -map 0:49 -map 0:50 -map 0:51 -map 0:52 -map 0:53 -map 0:54 -map 0:55 -map 0:56 -map 0:1 -map 1:2 -map 1:3 -c copy -map_metadata 0 -avoid_negative_ts make_zero C:\Users\xiyun\Downloads\[ACESSE...HD-ELITE.ME]...Paprika.2006.BluRay.1080p.x264.DTS.5.1.Dual\Paprika.2006.BluRay.1080p.x264.DTS.5.1.Dual\Paprika.2006.BluRay.1080p.x264.DTS.5.1.Dual part 0_1.mp4

INFORMAÇÕES: Stream map '' matches no streams.
nov. 08, 2024 1:20:31 PM data.CommandRunnerImp runCommand$lambda$0
INFORMAÇÕES: To ignore this, add a trailing '?' to the map.
nov. 08, 2024 1:20:31 PM data.CommandRunnerImp runCommand$lambda$0
INFORMAÇÕES: Failed to set value '0:5' for option 'map': Invalid argument
nov. 08, 2024 1:20:31 PM data.CommandRunnerImp runCommand$lambda$0
INFORMAÇÕES: Error parsing options for output file C:\Users\xiyun\Downloads\[ACESSE...HD-ELITE.ME]...Paprika.2006.BluRay.1080p.x264.DTS.5.1.Dual\Paprika.2006.BluRay.1080p.x264.DTS.5.1.Dual\Paprika.2006.BluRay.1080p.x264.DTS.5.1.Dual part 0_1.mp4.
nov. 08, 2024 1:20:31 PM data.CommandRunnerImp runCommand$lambda$0
INFORMAÇÕES: Error opening output files: Invalid argument