/*
 * SPDX-FileCopyrightText: 2024 TPJ Schikhof <kde@schikhof.eu>
 *
 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
package org.kde.kdeconnect.Helpers

import java.net.MalformedURLException
import java.net.URL

object VideoUrlsHelper {
    private const val SECONDS_IN_MINUTE = 60
    private const val MINUTES_IN_HOUR = 60
    private const val SECONDS_IN_HOUR = SECONDS_IN_MINUTE * MINUTES_IN_HOUR

    @Throws(MalformedURLException::class)
    fun formatUriWithSeek(address: String, position: Long): URL {
        val positionSeconds = position / 1000 // milliseconds to seconds
        val url = URL(address)
        if (positionSeconds <= 0) {
            return url // nothing to do
        }
        val host = url.host.lowercase()

        return when {
            listOf("youtube.com", "youtu.be", "pornhub.com").any { site -> site in host } -> {
                url.editParameter("t", Regex("\\d+")) { "$positionSeconds" }
            }
            host.contains("vimeo.com") -> {
                url.editParameter("t", Regex("\\d+s")) { "${positionSeconds}s" }
            }
            host.contains("dailymotion.com") -> {
                url.editParameter("start", Regex("\\d+")) { "$positionSeconds" }
            }
            host.contains("twitch.tv") -> {
                url.editParameter("t", Regex("(\\d+[hH])?(\\d+[mM])?\\d+[sS]")) { positionSeconds.formatTimestampHMS() }
            }
            else -> url
        }
    }

    private fun URL.editParameter(parameter: CharSequence, valuePattern: Regex?, parameterValueModifier: (String) -> String): URL {
        // "https://www.youtube.com/watch?v=ovX5G0O5ZvA&t=13" -> ["https://www.youtube.com/watch", "v=ovX5G0O5ZvA&t=13"]
        val urlSplit = this.toString().split("?")
        if (urlSplit.size != 2) {
            return this
        }
        val (urlBase, urlQuery) = urlSplit
        val modifiedUrlQuery = urlQuery
            .split("&") // "v=ovX5G0O5ZvA&t=13" -> ["v=ovX5G0O5ZvA", "t=13"]
            .map { it.split("=", limit = 2) } // […, "t=13"] -> […, ["t", "13"]]
            .map { Pair(it.first(), it.lastOrNull() ?: return this) }
            .map { paramAndValue ->
                // Modify matching parameter and optionally matches the old value with the provided pattern
                if (paramAndValue.first == parameter && valuePattern?.matches(paramAndValue.second) != false) {
                    Pair(paramAndValue.first, parameterValueModifier(paramAndValue.second)) // ["t", "13"] -> ["t", result]
                } else {
                    paramAndValue
                }
            }
            .joinToString("&") { "${it.first}=${it.second}" } // [["v", "ovX5G0O5ZvA"], ["t", "14"]] -> "v=ovX5G0O5ZvA&t=14"
        return URL("${urlBase}?${modifiedUrlQuery}") // -> "https://www.youtube.com/watch?v=ovX5G0O5ZvA&t=14"
    }

    /** Formats timestamp to e.g. 01h02m34s */
    private fun Long.formatTimestampHMS(): String {
        if (this == 0L) return "0s"

        val seconds: Long = this % SECONDS_IN_MINUTE
        val minutes: Long = (this / SECONDS_IN_MINUTE) % MINUTES_IN_HOUR
        val hours: Long = this / SECONDS_IN_HOUR

        fun pad(s: String) = s.padStart(3, '0')
        val hoursText = if (hours > 0) pad("${hours}h") else ""
        val minutesText = if (minutes > 0 || hours > 0) pad("${minutes}m") else ""
        val secondsText = pad("${seconds}s")

        return "${hoursText}${minutesText}${secondsText}"
    }
}
