package ru.forbion.f7cloud.feature.talknative

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.util.Log
import android.widget.Toast
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import ru.f7cloud.talk.activities.CallActivity
import ru.f7cloud.talk.services.CallForegroundService
import ru.f7cloud.talk.utils.bundle.BundleKeys
import ru.f7cloud.talk.utils.singletons.ApplicationWideCurrentRoomHolder
import ru.f7cloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_DISPLAY_NAME
import ru.f7cloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_NAME
import ru.f7cloud.talk.utils.bundle.BundleKeys.KEY_IS_MODERATOR
import ru.f7cloud.talk.utils.bundle.BundleKeys.KEY_RECORDING_STATE
import ru.forbion.f7cloud.core.auth.AuthSession

/**
 * Launches Talk calls via native WebRTC ([CallActivity]), same as F7cloud Talk Android.
 */
object TalkNativeCallLauncher {
    private const val TAG = "TalkNativeCallLauncher"
    private const val WEBVIEW_CALL_ACTIVITY = "ru.forbion.f7cloud.feature.talk.TalkCallActivity"

    // Main-scope для запуска звонка после suspend-подготовки vendor-юзера (IO)
    private val launchScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)

    fun launchIncomingCall(
        context: Context,
        session: AuthSession,
        acceptUrl: String,
        roomDisplayName: String? = null,
    ) {
        val roomToken = extractRoomToken(stripDirectCallHash(acceptUrl)) ?: run {
            showError(context, "Некорректная ссылка звонка")
            return
        }
        launchRoomCall(
            context = context,
            session = session,
            callContext = TalkNativeCallContext(
                roomToken = roomToken,
                displayName = roomDisplayName.orEmpty(),
                joinExistingCall = true,
            ),
            incomingFromNotification = true,
            suppressIncomingRingtone = true,
        )
    }

    fun launchRoomCall(context: Context, session: AuthSession, roomToken: String) {
        launchRoomCall(
            context = context,
            session = session,
            callContext = TalkNativeCallContext(roomToken = roomToken.trim()),
            incomingFromNotification = false,
        )
    }

    fun launchRoomCall(context: Context, session: AuthSession, callContext: TalkNativeCallContext) {
        launchRoomCall(
            context = context,
            session = session,
            callContext = callContext,
            incomingFromNotification = callContext.joinExistingCall,
        )
    }

    private fun launchRoomCall(
        context: Context,
        session: AuthSession,
        callContext: TalkNativeCallContext,
        incomingFromNotification: Boolean,
        suppressIncomingRingtone: Boolean = false,
    ) {
        if (!TalkNativeConfig.useNativeWebRtc) {
            if (TalkNativeConfig.allowWebViewCallFallback) {
                launchWebViewFallback(
                    context,
                    session,
                    callContext.roomToken.trim(),
                    incomingFromNotification,
                )
            } else {
                showError(context, "Нативные звонки отключены")
            }
            return
        }
        val token = callContext.roomToken.trim()
        if (token.isBlank()) {
            showError(context, "Некорректная комната звонка")
            return
        }
        // Подготовка vendor-юзера — suspend (IO): раньше runBlocking держал main
        // на пути звонка (ANR-риск на входящем звонке, аудит C4). Запуск activity — на main.
        launchScope.launch {
            if (!TalkVendorBootstrap.ensureSessionReady(context, session)) {
                showError(context, "Не удалось подготовить Talk для звонка")
                return@launch
            }
            runCatching {
                startCallActivity(
                    context,
                    buildCallIntent(context, session, callContext, incomingFromNotification, suppressIncomingRingtone),
                )
            }.onFailure { error ->
                Log.e(TAG, "Native CallActivity launch failed", error)
                if (TalkNativeConfig.allowWebViewCallFallback) {
                    launchWebViewFallback(context, session, token, incomingFromNotification)
                } else {
                    showError(context, "Не удалось начать звонок")
                }
            }
        }
    }

    private fun buildCallIntent(
        context: Context,
        session: AuthSession,
        callContext: TalkNativeCallContext,
        incomingFromNotification: Boolean,
        suppressIncomingRingtone: Boolean = false,
    ): Intent =
        Intent(context, CallActivity::class.java).apply {
            putExtra(BundleKeys.KEY_ROOM_TOKEN, callContext.roomToken.trim())
            putExtra(BundleKeys.KEY_MODIFIED_BASE_URL, session.serverUrl.trimEnd('/'))
            val displayName = callContext.displayName.trim()
            putExtra(KEY_CONVERSATION_NAME, displayName)
            putExtra(KEY_CONVERSATION_DISPLAY_NAME, displayName)
            putExtra(BundleKeys.KEY_ROOM_ONE_TO_ONE, callContext.isOneToOne)
            putExtra(BundleKeys.KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_AUDIO, true)
            putExtra(BundleKeys.KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_VIDEO, true)
            putExtra(KEY_IS_MODERATOR, true)
            putExtra(KEY_RECORDING_STATE, 0)
            putExtra(BundleKeys.KEY_CALL_VOICE_ONLY, callContext.isVoiceOnly)
            if (incomingFromNotification) {
                putExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, true)
            }
            if (suppressIncomingRingtone) {
                putExtra(BundleKeys.KEY_SUPPRESS_INCOMING_RINGTONE, true)
            }
        }

    private fun startCallActivity(context: Context, intent: Intent) {
        val appContext = context.applicationContext
        ApplicationWideCurrentRoomHolder.getInstance().clear()
        CallForegroundService.stop(appContext)
        if (context !is Activity) {
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        }
        // CallActivity is singleTask; onNewIntent restarts when a previous call screen is still alive.
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
        context.startActivity(intent)
    }

    private fun launchWebViewFallback(
        context: Context,
        session: AuthSession,
        roomToken: String,
        autoJoin: Boolean,
    ) {
        val callUrl = "${session.serverUrl.trimEnd('/')}/call/$roomToken"
        val intent = Intent().apply {
            setClassName(context, WEBVIEW_CALL_ACTIVITY)
            if (context !is Activity) {
                addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            }
            putExtra("url", callUrl)
            putExtra("title", if (autoJoin) "Входящий звонок" else "Звонок")
            putExtra("username", session.username)
            putExtra("password", session.appPassword)
            putExtra("server_url", session.serverUrl)
            putExtra("trust_all_certs", session.trustAllCerts)
            putExtra("auto_join", autoJoin)
        }
        context.startActivity(intent)
    }

    private fun showError(context: Context, message: String) {
        Toast.makeText(context.applicationContext, message, Toast.LENGTH_LONG).show()
    }

    private fun stripDirectCallHash(url: String): String {
        val hash = url.indexOf('#')
        return if (hash >= 0) url.substring(0, hash) else url
    }

    private fun extractRoomToken(url: String): String? {
        val path = runCatching { android.net.Uri.parse(url).path }.getOrNull() ?: url
        val marker = "/call/"
        val idx = path.indexOf(marker)
        if (idx < 0) return null
        val rest = path.substring(idx + marker.length)
        val end = rest.indexOfFirst { it == '/' || it == '?' || it == '#' }.let { if (it < 0) rest.length else it }
        return rest.substring(0, end).ifBlank { null }
    }
}
