package ac.mdiq.podcini.ui.screens.prefscreens

import ac.mdiq.podcini.PodciniApp.Companion.forceRestart
import ac.mdiq.podcini.PodciniApp.Companion.getAppContext
import ac.mdiq.podcini.R
import ac.mdiq.podcini.config.settings.MediaFilesTransporter
import ac.mdiq.podcini.net.feed.FeedUpdateManager.checkAndScheduleUpdateTaskOnce
import ac.mdiq.podcini.net.feed.FeedUpdateManager.getInitialDelay
import ac.mdiq.podcini.net.feed.FeedUpdateManager.nextRefreshTime
import ac.mdiq.podcini.net.sync.SyncService
import ac.mdiq.podcini.net.sync.SynchronizationCredentials
import ac.mdiq.podcini.net.sync.SynchronizationProviderViewData
import ac.mdiq.podcini.net.sync.SynchronizationSettings
import ac.mdiq.podcini.net.sync.SynchronizationSettings.isProviderConnected
import ac.mdiq.podcini.net.sync.SynchronizationSettings.setSelectedSyncProvider
import ac.mdiq.podcini.net.sync.SynchronizationSettings.setWifiSyncEnabled
import ac.mdiq.podcini.net.sync.nextcloud.NextcloudLoginFlow
import ac.mdiq.podcini.net.sync.nextcloud.NextcloudLoginFlow.AuthenticationCallback
import ac.mdiq.podcini.net.sync.wifi.WifiSyncService.Companion.startInstantSync
import ac.mdiq.podcini.shared.PodciniHttpClient
import ac.mdiq.podcini.shared.PodciniHttpClient.getKtorClient
import ac.mdiq.podcini.shared.PodciniHttpClient.resetClient
import ac.mdiq.podcini.shared.ProxyConfig
import ac.mdiq.podcini.sources.discoverSources
import ac.mdiq.podcini.storage.database.appAttribs
import ac.mdiq.podcini.storage.database.appPrefs
import ac.mdiq.podcini.storage.database.proxyConfig
import ac.mdiq.podcini.storage.database.upsert
import ac.mdiq.podcini.storage.database.upsertBlk
import ac.mdiq.podcini.storage.utils.deleteDirectoryRecursively
import ac.mdiq.podcini.storage.utils.findRootForUri
import ac.mdiq.podcini.storage.utils.mediaDir
import ac.mdiq.podcini.storage.utils.persistedTrees
import ac.mdiq.podcini.storage.utils.toAndroidUri
import ac.mdiq.podcini.storage.utils.toSafeUri
import ac.mdiq.podcini.storage.utils.toUF
import ac.mdiq.podcini.ui.compose.ComfirmDialog
import ac.mdiq.podcini.ui.compose.CommonPopupCard
import ac.mdiq.podcini.ui.compose.CustomTextStyles
import ac.mdiq.podcini.ui.compose.NumberEditor
import ac.mdiq.podcini.ui.compose.Spinner
import ac.mdiq.podcini.ui.compose.TitleSummaryActionColumn
import ac.mdiq.podcini.ui.compose.TitleSummarySwitchRow
import ac.mdiq.podcini.ui.compose.textColor
import ac.mdiq.podcini.utils.EventFlow
import ac.mdiq.podcini.utils.FlowEvent
import ac.mdiq.podcini.utils.Logd
import ac.mdiq.podcini.utils.Loge
import ac.mdiq.podcini.utils.Logs
import ac.mdiq.podcini.utils.Logt
import android.app.Activity.RESULT_OK
import android.content.Context.WIFI_SERVICE
import android.content.Intent
import android.net.Uri
import android.net.wifi.WifiManager
import android.util.Patterns
import androidx.activity.compose.BackHandler
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Checkbox
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.compose.LocalLifecycleOwner
import io.github.xilinjia.krdb.ext.toRealmSet
import io.ktor.client.HttpClient
import io.ktor.client.engine.okhttp.OkHttp
import io.ktor.client.plugins.HttpTimeout
import io.ktor.client.request.request
import io.ktor.http.HttpMethod
import io.ktor.http.isSuccess
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.io.IOException
import java.net.InetSocketAddress
import java.net.Proxy
import java.net.SocketAddress

private const val TAG = "NetworkPreferences"

@Suppress("EnumEntryName")
enum class MobileUpdateOptions(val res: Int) {
    feed_refresh(R.string.pref_mobileUpdate_refresh),
    episode_download(R.string.pref_mobileUpdate_episode_download),
    auto_download(R.string.pref_mobileUpdate_auto_download),
    streaming(R.string.pref_mobileUpdate_streaming),
    images(R.string.pref_mobileUpdate_images),
    sync(R.string.synchronization_pref);
}

@Composable
fun NetworkStorageScreen() {
    val context by rememberUpdatedState(LocalContext.current)
    BackHandler(enabled = true) { pfBackStack.removeLastOrNull() }

    @Composable
    fun ProxyDialog(onDismiss: ()->Unit) {
        val types = remember { mutableStateListOf<String>() }
        val textColor = MaterialTheme.colorScheme.onSurface
        LaunchedEffect(Unit) {
            types.add(Proxy.Type.DIRECT.name)
            types.add(Proxy.Type.HTTP.name)
            types.add(Proxy.Type.SOCKS.name)
        }
        var testSuccessful by remember { mutableStateOf(false) }
        var type by remember { mutableStateOf(proxyConfig.type.name) }
        var typePos by remember { mutableIntStateOf(0) }
        var host by remember { mutableStateOf(proxyConfig.host?:"") }
        var port by remember { mutableStateOf(if (proxyConfig.port > 0) proxyConfig.port.toString() else "") }
        var portValue by remember { mutableIntStateOf(proxyConfig.port) }
        var username by remember { mutableStateOf(proxyConfig.username) }
        var password by remember { mutableStateOf(proxyConfig.password) }
        var message by remember { mutableStateOf("") }
        var messageColor by remember { mutableStateOf(textColor) }
        var showOKButton by remember { mutableStateOf(false) }
        var okButtonTextRes by remember { mutableIntStateOf(R.string.proxy_test_label) }

        fun configProxy() {
            val typeEnum = Proxy.Type.valueOf(type)
            if (username.isNullOrEmpty()) username = null
            if (password.isNullOrEmpty()) password = null
            if (port.isNotEmpty()) portValue = port.toInt()
            val config = ProxyConfig(typeEnum, host, portValue, username, password)
            proxyConfig = config
            PodciniHttpClient.configProxy(config)
        }
        fun setTestRequired(required: Boolean) {
            if (required) {
                testSuccessful = false
                okButtonTextRes = R.string.proxy_test_label
            } else {
                testSuccessful = true
                okButtonTextRes = android.R.string.ok
            }
        }
        fun checkHost(): Boolean {
            if (host.isEmpty()) {
                Loge(TAG, context.getString(R.string.proxy_host_empty_error))
                return false
            }
            if ("localhost" != host && !Patterns.DOMAIN_NAME.matcher(host).matches()) {
                Loge(TAG, context.getString(R.string.proxy_host_invalid_error))
                return false
            }
            return true
        }
        fun checkPort(): Boolean {
            if (portValue !in 0..65535) {
                Loge(TAG, "context.getString(R.string.proxy_port_invalid_error)")
                return false
            }
            return true
        }
        fun checkValidity(): Boolean {
            var valid = true
            if (typePos > 0) valid = checkHost()
            valid = valid and checkPort()
            return valid
        }
        fun test() {
            if (!checkValidity()) {
                setTestRequired(true)
                return
            }
            val checking = context.getString(R.string.proxy_checking)
            messageColor = textColor
            message = "{faw_circle_o_notch spin} $checking"
            val coroutineScope = CoroutineScope(Dispatchers.Main)
            coroutineScope.launch(Dispatchers.IO) {
                try {
                    if (port.isNotEmpty()) portValue = port.toInt()
                    val address: SocketAddress = InetSocketAddress.createUnresolved(host, portValue)
                    val proxyType = Proxy.Type.valueOf(type.uppercase())
                    HttpClient(OkHttp) {
                        install(HttpTimeout) { connectTimeoutMillis = 10_000 }
                        engine { config { proxy(Proxy(proxyType, address)) } }
                    }.use { client ->
                        try {
                            val response = client.request("https://www.example.com") { method = HttpMethod.Get }
                            if (!response.status.isSuccess()) throw IOException(response.status.description)
                        } catch (e: IOException) { throw e }
                    }
                    withContext(Dispatchers.Main) {
                        message = context.getString(R.string.proxy_test_successful)
                        messageColor = Color.Green
                        setTestRequired(false)
                    }
                } catch (e: Throwable) {
                    Logs("DownloadsPreferencesScreen", e)
                    messageColor = Color.Red
                    message = context.getString(R.string.proxy_test_failed) + ":" + e.message
                    setTestRequired(true)
                }
            }
        }
        AlertDialog(modifier = Modifier.border(1.dp, MaterialTheme.colorScheme.tertiary, MaterialTheme.shapes.extraLarge), onDismissRequest = { onDismiss() },
            title = { Text(stringResource(R.string.pref_proxy_title), style = CustomTextStyles.titleCustom) },
            text = {
                Column {
                    Row(verticalAlignment = Alignment.CenterVertically) {
                        Text(stringResource(R.string.proxy_type_label))
                        Spinner(items = types, selectedItem = proxyConfig.type.name) { position ->
                            val name = Proxy.Type.entries.getOrNull(position)?.name
                            if (!name.isNullOrBlank()) {
                                typePos = position
                                type = name
                                showOKButton = position != 0
                                setTestRequired(position > 0)
                            }
                        }
                    }
                    if (typePos > 0) {
                        Row(verticalAlignment = Alignment.CenterVertically) {
                            Text(stringResource(R.string.host_label))
                            TextField(value = host, label = { Text("www.example.com") }, isError = !checkHost(), modifier = Modifier.fillMaxWidth(),
                                onValueChange = { host = it }
                            )
                        }
                        Row(verticalAlignment = Alignment.CenterVertically) {
                            Text(stringResource(R.string.port_label))
                            TextField(value = port, label = { Text("8080") }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), isError = !checkPort(), modifier = Modifier.fillMaxWidth(),
                                onValueChange = {
                                    port = it
                                    portValue = it.toIntOrNull() ?: -1
                                }
                            )
                        }
                        Row(verticalAlignment = Alignment.CenterVertically) {
                            Text(stringResource(R.string.username_label))
                            TextField(value = username ?: "", label = { Text(stringResource(R.string.optional_hint)) }, modifier = Modifier.fillMaxWidth(),
                                onValueChange = { username = it }
                            )
                        }
                        Row(verticalAlignment = Alignment.CenterVertically) {
                            Text(stringResource(R.string.password_label))
                            TextField(value = password ?: "", label = { Text(stringResource(R.string.optional_hint)) }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), modifier = Modifier.fillMaxWidth(),
                                onValueChange = { password = it }
                            )
                        }
                    }
                    if (message.isNotBlank()) Text(message, color = messageColor)
                }
            },
            confirmButton = {
                if (showOKButton) TextButton(onClick = {
                    if (!testSuccessful) {
                        test()
                        return@TextButton
                    }
                    configProxy()
                    resetClient()
                    onDismiss()
                }) { Text(stringResource(okButtonTextRes)) }
            },
            dismissButton = { TextButton(onClick = { onDismiss() }) { Text(stringResource(R.string.cancel_label)) } }
        )
    }

    var showProxyDialog by remember { mutableStateOf(false) }
    if (showProxyDialog) ProxyDialog {showProxyDialog = false }
    val showImporSuccessDialog = remember { mutableStateOf(false) }
    ComfirmDialog(titleRes = R.string.successful_import_label, message = stringResource(R.string.import_ok), showDialog = showImporSuccessDialog, cancellable = false) { forceRestart() }

    var showProgress by remember { mutableStateOf(false) }
    if (showProgress) {
        CommonPopupCard(onDismiss = { showProgress = false }) {
            Box(contentAlignment = Alignment.Center) {
                CircularProgressIndicator(strokeWidth = 10.dp, color = textColor, modifier = Modifier.size(50.dp).align(Alignment.TopCenter))
                Text("Loading...", color = textColor, modifier = Modifier.align(Alignment.BottomCenter))
            }
        }
    }

    Logd(TAG, "useCustomMediaFolder: ${appPrefs.useCustomMediaFolder} customMediaUri: ${appPrefs.customMediaUri}")
    val selectCustomMediaDirLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        if (result.resultCode == RESULT_OK) {
            val uri: Uri? = result.data?.data
            Logd(TAG, "selectCustomMediaDirLauncher the chosen uri: $uri")
            if (uri != null) {
                showProgress = true
                CoroutineScope(Dispatchers.IO).launch {
                    getAppContext().contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
                    persistedTrees.add(uri)
                    val dir = uri.toUF()
                    dir.listChildren().forEach {
                        Logd(TAG, "clearing destination: ${it.absPath}")
                        deleteDirectoryRecursively(it)
                    }
                    val mediaDir_ = uri.toUF().createDirectory("Podcini.media")
                    MediaFilesTransporter("Podcini.media").fromMediaDirToUF(mediaDir_, move = true, useSubDir = false)
                    deleteDirectoryRecursively(mediaDir)
                    upsert(appPrefs) { ap ->
                        ap.useCustomMediaFolder = true
                        ap.customMediaUri = mediaDir_.toAndroidUri().toString()
                        ap.customFolderUnavailable = false
                    }
                    showProgress = false
                    showImporSuccessDialog.value = true
                }
            } else Loge("selectCustomMediaDirLauncher", "uri is null")
        } else Logt(TAG, "custom dir not chosen")
    }

    var refreshInterval by remember { mutableStateOf(appPrefs.autoUpdateInterval.toString()) }
    LaunchedEffect(Unit) { getInitialDelay() }

    Column(modifier = Modifier.fillMaxWidth().padding(start = 16.dp, end = 16.dp).verticalScroll(rememberScrollState()).background(MaterialTheme.colorScheme.surface)) {
        Column(modifier = Modifier.fillMaxWidth().padding(start = 16.dp, top = 10.dp)) {
            Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
                Text(stringResource(R.string.identifier), color = textColor, style = CustomTextStyles.titleCustom, fontWeight = FontWeight.Bold, modifier = Modifier.wrapContentWidth())
                var name by remember(appAttribs.name) { mutableStateOf(appAttribs.name) }
                var showIcon by remember { mutableStateOf(false) }
                TextField(value = name, modifier = Modifier.weight(1f).padding(start = 8.dp),
                    onValueChange = {
                        name = it
                        showIcon = true
                    },
                    trailingIcon = {
                        if (showIcon) Icon(imageVector = Icons.Filled.Settings, contentDescription = "Settings", modifier = Modifier.size(30.dp).clickable {
                            upsertBlk(appAttribs) { it.name = name }
                            showIcon =  false })
                })
            }
            Text(stringResource(R.string.network_identifier_sum), color = textColor, style = MaterialTheme.typography.bodySmall)
        }
        TitleSummarySwitchRow(R.string.pref_use_external_app, R.string.pref_use_external_app_sum, appPrefs.loadExternalApp) {
            upsertBlk(appPrefs) { p-> p.loadExternalApp = it}
            discoverSources(it)
        }
        Column(modifier = Modifier.fillMaxWidth().padding(start = 16.dp, top = 10.dp)) {
            Row(verticalAlignment = Alignment.CenterVertically) {
                Text(stringResource(R.string.feed_refresh_title), color = textColor, style = CustomTextStyles.titleCustom, fontWeight = FontWeight.Bold, modifier = Modifier.weight(1f))
                NumberEditor(refreshInterval.toInt(), stringResource(R.string.time_minutes), nz = false, modifier = Modifier.weight(0.6f)) {
                    refreshInterval = it.toString()
                    Logd("DownloadsSetting", "refreshInterval: $refreshInterval")
                    upsertBlk(appPrefs) { p-> p.autoUpdateInterval = it }
                    checkAndScheduleUpdateTaskOnce(replace = true, force = it > 0)
                }
            }
            Text(stringResource(R.string.feed_refresh_sum), color = textColor, style = MaterialTheme.typography.bodySmall)
            if (refreshInterval != "0") Text(stringResource(R.string.feed_next_refresh_time) + " " + nextRefreshTime, color = textColor, style = MaterialTheme.typography.bodySmall)
        }
        TitleSummarySwitchRow(R.string.pref_fetch_media_size, R.string.pref_fetch_media_size_sum, appPrefs.fetchmediaSizes) {
            upsertBlk(appPrefs) { p-> p.fetchmediaSizes = it}
        }
        TitleSummarySwitchRow(R.string.pref_watch_storage_title, R.string.pref_watch_storage_sum, appPrefs.checkAvailableSpace) {
            upsertBlk(appPrefs) { p-> p.checkAvailableSpace = it}
        }
        var showResetCustomFolderDialog by remember { mutableStateOf(false) }
        if (showResetCustomFolderDialog) {
            AlertDialog(modifier = Modifier.border(1.dp, MaterialTheme.colorScheme.tertiary, MaterialTheme.shapes.extraLarge), onDismissRequest = { showResetCustomFolderDialog = false },
                title = { Text(stringResource(R.string.pref_custom_media_dir_title), style = CustomTextStyles.titleCustom) },
                text = { Text(stringResource(R.string.pref_custom_media_dir_sum2), color = textColor, style = MaterialTheme.typography.bodySmall) },
                confirmButton = {
                    TextButton(onClick = {
                        showProgress = true
                        CoroutineScope(Dispatchers.IO).launch {
                            val uf = appPrefs.customMediaUri.toUF()
                            upsert(appPrefs) {
                                it.useCustomMediaFolder = false
                                it.customMediaUri = ""
                                it.customFolderUnavailable = false
                            }
                            MediaFilesTransporter("").fromUFToMediaDir(uf, move = true, verify = false)
                            deleteDirectoryRecursively(uf)
                            findRootForUri(appPrefs.customMediaUri.toSafeUri())?.let {
                                try { getAppContext().contentResolver.releasePersistableUriPermission(it, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION) } catch (e: Exception) { Logd(TAG, "uri can not be released: $it")}
                            }
                            showProgress = false
                            showImporSuccessDialog.value = true
                            showResetCustomFolderDialog = false
                        }
                    }) { Text(stringResource(R.string.reset)) }
                },
                dismissButton = { TextButton(onClick = { showResetCustomFolderDialog = false }) { Text(stringResource(R.string.cancel_label)) } }
            )
        }
        var showSetCustomFolderDialog by remember { mutableStateOf(false) }
        if (showSetCustomFolderDialog) {
            val sumTextRes = if (appPrefs.useCustomMediaFolder) R.string.pref_custom_media_dir_sum1 else R.string.pref_custom_media_dir_sum
            AlertDialog(modifier = Modifier.border(1.dp, MaterialTheme.colorScheme.tertiary, MaterialTheme.shapes.extraLarge), onDismissRequest = { showSetCustomFolderDialog = false },
                title = { Text(stringResource(R.string.pref_custom_media_dir_title), style = CustomTextStyles.titleCustom) },
                text = { Text(stringResource(sumTextRes), color = textColor, style = MaterialTheme.typography.bodySmall) },
                confirmButton = {
                    TextButton(onClick = {
                        try {
                            val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
                            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
                            intent.addCategory(Intent.CATEGORY_DEFAULT)
                            selectCustomMediaDirLauncher.launch(intent)
                            showSetCustomFolderDialog = false
                        } catch (e: Exception) { Loge(TAG, "Can't select custom dir: ${e.message}")}
                    }) { Text(stringResource(R.string.confirm_label)) }
                },
                dismissButton = { TextButton(onClick = { showSetCustomFolderDialog = false }) { Text(stringResource(R.string.cancel_label)) } }
            )
        }
        Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth().padding(start = 16.dp, top = 10.dp)) {
            Column(modifier = Modifier.weight(1f).clickable { showSetCustomFolderDialog = true }) {
                Text(stringResource(R.string.pref_custom_media_dir_title), color = textColor, style = CustomTextStyles.titleCustom, fontWeight = FontWeight.Bold)
                Text(appPrefs.customMediaUri.ifBlank { stringResource(R.string.pref_custom_media_dir_sum) }, color = textColor, style = MaterialTheme.typography.bodySmall)
            }
            if (appPrefs.useCustomMediaFolder) TextButton(onClick = { showResetCustomFolderDialog = true }) { Text(stringResource(R.string.reset)) }
        }
        HorizontalDivider(color = MaterialTheme.colorScheme.onTertiaryContainer, thickness = 1.dp)
        TitleSummarySwitchRow(R.string.pref_automatic_download_title, R.string.pref_automatic_download_sum, appPrefs.enableAutoDl) {
            upsertBlk(appPrefs) { p -> p.enableAutoDl = it }
        }
        if (appPrefs.enableAutoDl) {
            Column(modifier = Modifier.fillMaxWidth().padding(start = 16.dp, top = 10.dp)) {
                Row(verticalAlignment = Alignment.CenterVertically) {
                    Text(stringResource(R.string.pref_episode_cache_title), color = textColor, style = CustomTextStyles.titleCustom, fontWeight = FontWeight.Bold, modifier = Modifier.weight(1f))
                    NumberEditor(appPrefs.episodeCacheSize, label = "integer", nz = false, modifier = Modifier.weight(0.5f)) {
                        upsertBlk(appPrefs) { p-> p.episodeCacheSize = it}
                    }
                }
                Text(stringResource(R.string.pref_episode_cache_summary), color = textColor, style = MaterialTheme.typography.bodySmall)
            }
            var showCleanupOptions by remember { mutableStateOf(false) }
            TitleSummaryActionColumn(R.string.pref_episode_cleanup_title, R.string.pref_episode_cleanup_summary) { showCleanupOptions = true }
            if (showCleanupOptions) {
                var tempCleanupOption by remember { mutableStateOf(appPrefs.episodeCleanup) }
                var interval by remember { mutableStateOf(appPrefs.episodeCleanup) }
                if ((interval.toIntOrNull() ?: -1) > 0) tempCleanupOption = EpisodeCleanupOptions.LimitBy.num.toString()
                AlertDialog(modifier = Modifier.border(1.dp, MaterialTheme.colorScheme.tertiary, MaterialTheme.shapes.extraLarge), onDismissRequest = { showCleanupOptions = false },
                    title = { Text(stringResource(R.string.pref_episode_cleanup_title), style = CustomTextStyles.titleCustom) },
                    text = {
                        Column {
                            EpisodeCleanupOptions.entries.forEach { option ->
                                Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth().padding(2.dp)
                                    .clickable { tempCleanupOption = option.num.toString() }) {
                                    Checkbox(checked = tempCleanupOption == option.num.toString(), onCheckedChange = { tempCleanupOption = option.num.toString() })
                                    Text(stringResource(option.res), modifier = Modifier.padding(start = 16.dp), style = MaterialTheme.typography.bodyMedium)
                                }
                            }
                            if (tempCleanupOption == EpisodeCleanupOptions.LimitBy.num.toString()) {
                                NumberEditor(interval.toInt(), label = "integer", modifier = Modifier.weight(0.6f)) { interval = it.toString() }
                            }
                        }
                    },
                    confirmButton = {
                        TextButton(onClick = {
                            var num = if (tempCleanupOption == EpisodeCleanupOptions.LimitBy.num.toString()) interval else tempCleanupOption
                            if (num.toIntOrNull() == null) num = EpisodeCleanupOptions.Never.num.toString()
                            upsertBlk(appPrefs) { it.episodeCleanup = num}
                            showCleanupOptions = false
                        }) { Text(text = "OK") }
                    },
                    dismissButton = { TextButton(onClick = { showCleanupOptions = false }) { Text(stringResource(R.string.cancel_label)) } }
                )
            }
            TitleSummarySwitchRow(R.string.pref_automatic_download_on_battery_title, R.string.pref_automatic_download_on_battery_sum, appPrefs.enableAutoDownloadOnBattery) {
                upsertBlk(appPrefs) { p-> p.enableAutoDownloadOnBattery = it}
            }
        }
        HorizontalDivider(color = MaterialTheme.colorScheme.onTertiaryContainer, thickness = 1.dp)

        var showMeteredNetworkOptions by remember { mutableStateOf(false) }
        TitleSummaryActionColumn(R.string.pref_metered_network_title, R.string.pref_mobileUpdate_sum) { showMeteredNetworkOptions = true }
        if (showMeteredNetworkOptions) {
            var tempSelectedOptions by remember { mutableStateOf(appPrefs.mobileUpdateTypes.toSet()) }
            fun updateSepections(option: MobileUpdateOptions) {
                tempSelectedOptions = if (tempSelectedOptions.contains(option.name)) tempSelectedOptions - option.name else tempSelectedOptions + option.name
                when (option) {
                    MobileUpdateOptions.auto_download if tempSelectedOptions.contains(option.name) -> {
                        tempSelectedOptions += MobileUpdateOptions.episode_download.name
                        tempSelectedOptions += MobileUpdateOptions.feed_refresh.name
                    }
                    MobileUpdateOptions.episode_download if !tempSelectedOptions.contains(option.name) -> tempSelectedOptions -= MobileUpdateOptions.auto_download.name
                    MobileUpdateOptions.feed_refresh if !tempSelectedOptions.contains(option.name) -> tempSelectedOptions -= MobileUpdateOptions.auto_download.name
                    else -> {}
                }
            }
            AlertDialog(modifier = Modifier.border(1.dp, MaterialTheme.colorScheme.tertiary, MaterialTheme.shapes.extraLarge), onDismissRequest = { showMeteredNetworkOptions = false },
                title = { Text(stringResource(R.string.pref_metered_network_title), style = CustomTextStyles.titleCustom) },
                text = {
                    Column {
                        MobileUpdateOptions.entries.forEach { option ->
                            Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth().padding(2.dp).clickable { updateSepections(option) }) {
                                Checkbox(checked = tempSelectedOptions.contains(option.name), onCheckedChange = { updateSepections(option) })
                                Text(stringResource(option.res), modifier = Modifier.padding(start = 16.dp), style = MaterialTheme.typography.bodyMedium)
                            }
                        }
                    }
                },
                confirmButton = {
                    TextButton(onClick = {
                        upsertBlk(appPrefs) { it.mobileUpdateTypes = tempSelectedOptions.toRealmSet() }
                        val optionsDiff = (tempSelectedOptions - appPrefs.mobileUpdateTypes) + (appPrefs.mobileUpdateTypes - tempSelectedOptions)
                        if (optionsDiff.contains(MobileUpdateOptions.feed_refresh.name) || optionsDiff.contains(MobileUpdateOptions.auto_download.name))
                            checkAndScheduleUpdateTaskOnce(replace = true, force = true)
                        showMeteredNetworkOptions = false
                    }) { Text(text = "OK") }
                },
                dismissButton = { TextButton(onClick = { showMeteredNetworkOptions = false }) { Text(stringResource(R.string.cancel_label)) } }
            )
        }
        TitleSummaryActionColumn(R.string.pref_proxy_title, R.string.pref_proxy_sum) { showProxyDialog = true }
        HorizontalDivider(color = MaterialTheme.colorScheme.onTertiaryContainer, thickness = 1.dp)
        SynchronizationScreen()
    }
}

enum class EpisodeCleanupOptions(val res: Int, val num: Int) {
    ExceptFavorites(R.string.episode_cleanup_except_favorite, -3),
    Never(R.string.episode_cleanup_never, -2),
    NotInQueue(R.string.episode_cleanup_not_in_queue, -1),
    LimitBy(R.string.episode_cleanup_limit_by, 0)
}

@Composable
fun SynchronizationScreen() {
    val context by rememberUpdatedState(LocalContext.current)
    BackHandler(enabled = true) { pfBackStack.removeLastOrNull() }

    val selectedSyncProviderKey: String = SynchronizationSettings.selectedSyncProviderKey?:""
    var selectedProvider by remember { mutableStateOf(SynchronizationProviderViewData.fromIdentifier(selectedSyncProviderKey)) }
    var loggedIn by remember { mutableStateOf(isProviderConnected) }

    @Composable
    fun NextcloudAuthenticationDialog(onDismiss: ()->Unit) {
        var nextcloudLoginFlow = remember<NextcloudLoginFlow?> { null }
        var showUrlEdit by remember { mutableStateOf(true) }
        var serverUrlText by remember { mutableStateOf(appPrefs.nextcloud_server_address) }
        var errorText by remember { mutableStateOf("") }
        var showChooseHost by remember { mutableStateOf(serverUrlText.isNotBlank()) }

        val nextCloudAuthCallback = object : AuthenticationCallback {
            override fun onNextcloudAuthenticated(server: String, username: String, password: String) {
                Logd("NextcloudAuthenticationDialog", "onNextcloudAuthenticated: $server")
                setSelectedSyncProvider(SynchronizationProviderViewData.NEXTCLOUD_GPODDER)
                SynchronizationCredentials.clear()
                SynchronizationCredentials.password = password
                SynchronizationCredentials.hosturl = server
                SynchronizationCredentials.username = username
                SyncService.fullSync()
                loggedIn = isProviderConnected
                onDismiss()
            }
            override fun onNextcloudAuthError(errorMessage: String?) {
                errorText = errorMessage ?: ""
                showChooseHost = true
                showUrlEdit = true
            }
        }

        val lifecycleOwner = LocalLifecycleOwner.current
        DisposableEffect(lifecycleOwner) {
            val observer = LifecycleEventObserver { _, event -> if (event == Lifecycle.Event.ON_RESUME) nextcloudLoginFlow?.poll() }
            lifecycleOwner.lifecycle.addObserver(observer)
            onDispose { lifecycleOwner.lifecycle.removeObserver(observer) }
        }

        AlertDialog(modifier = Modifier.border(1.dp, MaterialTheme.colorScheme.tertiary, MaterialTheme.shapes.extraLarge), onDismissRequest = { onDismiss() },
            title = { Text(stringResource(R.string.gpodnetauth_login_butLabel), style = CustomTextStyles.titleCustom) },
            text = {
                Column {
                    Text(stringResource(R.string.synchronization_host_explanation))
                    if (showUrlEdit) TextField(value = serverUrlText, modifier = Modifier.fillMaxWidth(), label = { Text(stringResource(R.string.synchronization_host_label)) },
                        onValueChange = {
                            serverUrlText = it
                            showChooseHost = serverUrlText.isNotBlank()
                        }
                    )
                    Text(stringResource(R.string.synchronization_nextcloud_authenticate_browser))
                    if (errorText.isNotBlank()) Text(errorText)
                }
            },
            confirmButton = {
                if (showChooseHost) TextButton(onClick = {
                    upsertBlk(appPrefs) { it.nextcloud_server_address = serverUrlText}
                    nextcloudLoginFlow = NextcloudLoginFlow(getKtorClient(), serverUrlText, getAppContext(), nextCloudAuthCallback)
                    errorText = ""
                    showChooseHost = false
                    nextcloudLoginFlow.start()
                    //                        onDismissRequest()
                }) { Text(stringResource(R.string.proceed_to_login_butLabel)) }
            },
            dismissButton = { TextButton(onClick = { onDismiss() }) { Text(stringResource(R.string.cancel_label)) } }
        )
    }

    var showNextCloudAuthDialog by remember { mutableStateOf(false) }
    if (showNextCloudAuthDialog) NextcloudAuthenticationDialog { showNextCloudAuthDialog = false }

    @Composable
    fun ChooseProviderAndLoginDialog(onDismiss: ()->Unit) {
        AlertDialog(modifier = Modifier.border(1.dp, MaterialTheme.colorScheme.tertiary, MaterialTheme.shapes.extraLarge), onDismissRequest = { onDismiss() },
            title = { Text(stringResource(R.string.dialog_choose_sync_service_title), style = CustomTextStyles.titleCustom) },
            text = {
                Column {
                    SynchronizationProviderViewData.entries.forEach { option ->
                        Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth().padding(2.dp)
                            .clickable {
                                when (option) {
                                    //                                    SynchronizationProviderViewData.GPODDER_NET -> GpodderAuthenticationFragment().show(activity.supportFragmentManager, GpodderAuthenticationFragment.TAG)
                                    SynchronizationProviderViewData.NEXTCLOUD_GPODDER -> showNextCloudAuthDialog = true
                                }
                                loggedIn = isProviderConnected
                                onDismiss()
                            }) {
                            Icon(painter = painterResource(id = option.iconResource), contentDescription = "", modifier = Modifier.size(40.dp).padding(end = 15.dp))
                            Text(stringResource(option.summaryResource), modifier = Modifier.padding(start = 16.dp), style = MaterialTheme.typography.bodyMedium)
                        }
                    }
                }
            },
            confirmButton = {},
            dismissButton = { TextButton(onClick = { onDismiss() }) { Text(stringResource(R.string.cancel_label)) } }
        )
    }

    @Composable
    fun WifiAuthenticationDialog(onDismiss: ()->Unit) {
        val TAG = "WifiAuthenticationDialog"

        val context by rememberUpdatedState(LocalContext.current)
        var progressMessage by remember { mutableStateOf("") }
        var errorMessage by remember { mutableStateOf("") }
        LaunchedEffect(Unit) {
            EventFlow.events.collectLatest { event ->
                Logd(TAG, "Received event: ${event.TAG}")
                when (event) {
                    is FlowEvent.SyncServiceEvent -> {
                        when (event.messageResId) {
                            R.string.sync_status_error -> {
                                errorMessage = event.message
                                Loge(TAG, errorMessage)
                                onDismiss()
                            }
                            R.string.sync_status_success -> {
                                Logt(TAG, context.getString(R.string.sync_status_success))
                                onDismiss()
                            }
                            R.string.sync_status_in_progress -> progressMessage = event.message
                            else -> Loge(TAG, "Sync result unknown ${event.messageResId}")
                        }
                    }
                    else -> {}
                }
            }
        }
        var portNum by remember { mutableIntStateOf(SynchronizationCredentials.hostport) }
        var isGuest by remember { mutableStateOf<Boolean?>(null) }
        var hostAddress by remember { mutableStateOf(SynchronizationCredentials.hosturl?:"") }
        var showHostAddress by remember { mutableStateOf(true)  }
        var portString by remember { mutableStateOf(SynchronizationCredentials.hostport.toString()) }
        var showProgress by remember { mutableStateOf(false) }
        var showConfirm by remember { mutableStateOf(true)  }
        var showCancel by remember { mutableStateOf(true)  }
        AlertDialog(modifier = Modifier.fillMaxWidth().border(1.dp, MaterialTheme.colorScheme.tertiary, MaterialTheme.shapes.extraLarge), onDismissRequest = { onDismiss() },
            title = { Text(stringResource(R.string.connect_to_peer), style = CustomTextStyles.titleCustom) },
            text = {
                Column {
                    Text(stringResource(R.string.wifisync_explanation_message), style = MaterialTheme.typography.bodySmall)
                    Row {
                        TextButton(onClick = {
                            val wifiManager = context.getSystemService(WIFI_SERVICE) as WifiManager
                            val ipAddress = wifiManager.connectionInfo.ipAddress
                            val ipString = "${ipAddress and 0xff}.${ipAddress shr 8 and 0xff}.${ipAddress shr 16 and 0xff}.${ipAddress shr 24 and 0xff}"
                            hostAddress = ipString
                            showHostAddress = false
                            portNum = portString.toInt()
                            isGuest = false
                            SynchronizationCredentials.hostport = portNum
                        }) { Text(stringResource(R.string.host_butLabel)) }
                        Spacer(Modifier.weight(1f))
                        TextButton(onClick = {
                            SynchronizationCredentials.hosturl = hostAddress
                            showHostAddress = true
                            portNum = portString.toInt()
                            isGuest = true
                            SynchronizationCredentials.hostport = portNum
                        }) { Text(stringResource(R.string.guest_butLabel)) }
                    }
                    Row {
                        if (showHostAddress) TextField(value = hostAddress, modifier = Modifier.weight(0.6f),
                            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
                            onValueChange = { input -> hostAddress = input },
                            label = { Text(stringResource(id = R.string.synchronization_host_address_label)) })
                        TextField(value = portString, modifier = Modifier.weight(0.4f).padding(start = 3.dp),
                            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
                            onValueChange = { input ->
                                portString = input
                                portNum = input.toInt()
                            },
                            label = { Text(stringResource(id = R.string.synchronization_host_port_label)) })
                    }
                    if (showProgress)  {
                        CircularProgressIndicator(strokeWidth = 10.dp, color = textColor, modifier = Modifier.size(50.dp))
                        Text(stringResource(R.string.wifisync_progress_message) + " " + progressMessage, color = textColor)
                    }
                    Text(errorMessage, style = MaterialTheme.typography.bodyMedium)
                }
            },
            confirmButton = {
                if (showConfirm) TextButton(onClick = {
                    Logd(TAG, "confirm button pressed")
                    if (isGuest == null) {
                        Logt(TAG, getAppContext().getString(R.string.host_or_guest))
                        return@TextButton
                    }
                    showProgress = true
                    showConfirm = false
                    showCancel = false
                    setWifiSyncEnabled(true)
                    startInstantSync(portNum, hostAddress, isGuest!!)
                }) { Text(stringResource(R.string.confirm_label)) }
            },
            dismissButton = { if (showCancel) TextButton(onClick = { onDismiss() }) { Text(stringResource(R.string.cancel_label)) } }
        )
    }

    var showWifiAuthenticationDialog by remember { mutableStateOf(false) }
    if (showWifiAuthenticationDialog) WifiAuthenticationDialog { showWifiAuthenticationDialog = false }

    var chooseProviderAndLoginDialog by remember { mutableStateOf(false) }
    if (chooseProviderAndLoginDialog) ChooseProviderAndLoginDialog { chooseProviderAndLoginDialog = false }

    //    fun isProviderSelected(provider: SynchronizationProviderViewData): Boolean {
    //        val selectedSyncProviderKey = selectedSyncProviderKey
    //        return provider.identifier == selectedSyncProviderKey
    //    }


    TitleSummaryActionColumn(R.string.wifi_sync, R.string.wifi_sync_summary_unchoosen) {
        showWifiAuthenticationDialog = true
    }
    Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth().padding(start = 10.dp, top = 10.dp)) {
        var titleRes by remember { mutableIntStateOf(0) }
        var summaryRes by remember { mutableIntStateOf(R.string.synchronization_summary_unchoosen) }
        var iconRes by remember { mutableIntStateOf(R.drawable.ic_notification_sync) }
        var onClick: (() -> Unit)? = null
        if (loggedIn) {
            selectedProvider = SynchronizationProviderViewData.fromIdentifier(selectedSyncProviderKey)
            if (selectedProvider != null) {
                summaryRes = selectedProvider!!.summaryResource
                iconRes = selectedProvider!!.iconResource
                Icon(painter = painterResource(id = iconRes), contentDescription = "", tint = textColor, modifier = Modifier.size(40.dp).padding(end = 15.dp))
            }
        } else {
            titleRes = R.string.synchronization_choose_title
            summaryRes = R.string.synchronization_summary_unchoosen
            iconRes = R.drawable.ic_cloud
            onClick = { chooseProviderAndLoginDialog = true }
            Icon(imageVector = ImageVector.vectorResource(iconRes), contentDescription = "", tint = textColor, modifier = Modifier.size(40.dp).padding(end = 15.dp))
        }
        TitleSummaryActionColumn(titleRes, summaryRes) { onClick?.invoke() }
    }
    if (loggedIn) {
        TitleSummaryActionColumn(R.string.synchronization_sync_changes_title, R.string.synchronization_sync_summary) { SyncService.syncImmediately() }
        TitleSummaryActionColumn(R.string.synchronization_full_sync_title, R.string.synchronization_force_sync_summary) { SyncService.fullSync() }
        TitleSummaryActionColumn(R.string.synchronization_logout, 0) {
            SynchronizationCredentials.clear()
            Logt("SynchronizationPreferencesScreen", context.getString(R.string.pref_synchronization_logout_toast))
            setSelectedSyncProvider(null)
            loggedIn = isProviderConnected
        }
    }
}

