package de.tsschulz.tt_tagebuch.app.ui

import android.annotation.SuppressLint
import android.view.ViewGroup
import android.webkit.WebChromeClient
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Arrangement
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.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.Card
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.DropdownMenu
import androidx.compose.material.DropdownMenuItem
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.OutlinedButton
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Switch
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import de.tsschulz.tt_tagebuch.app.AppDependencies
import de.tsschulz.tt_tagebuch.shared.api.http.ApiException
import de.tsschulz.tt_tagebuch.shared.api.models.ClickTtAccountDto
import de.tsschulz.tt_tagebuch.shared.api.models.ClickTtAccountStatusDto
import de.tsschulz.tt_tagebuch.shared.api.models.ClickTtAccountUpsertBody
import de.tsschulz.tt_tagebuch.shared.api.models.MyTischtennisAccountDto
import de.tsschulz.tt_tagebuch.shared.api.models.MyTischtennisAccountUpsertBody
import de.tsschulz.tt_tagebuch.shared.api.models.MyTischtennisStatusDto
import de.tsschulz.tt_tagebuch.shared.i18n.MobileStrings
import kotlinx.coroutines.launch
import java.net.URLEncoder
import java.nio.charset.StandardCharsets
import java.time.OffsetDateTime
import java.time.format.DateTimeFormatter
import java.util.UUID

private val PersonalHubPad = 20.dp
private val PersonalHubTouchMin = 48.dp

internal enum class PersonalHubDestination {
    PersonalLanguage,
    MyTischtennisAccount,
    ClickTtAccount,
    ClickTtBrowser,
}

@Composable
internal fun PersonalHubFlowScreen(
    destination: PersonalHubDestination,
    dependencies: AppDependencies,
    onBack: () -> Unit,
) {
    BackHandler(onBack = onBack)
    when (destination) {
        PersonalHubDestination.PersonalLanguage -> PersonalLanguageScreen(dependencies, onBack)
        PersonalHubDestination.MyTischtennisAccount -> MyTischtennisAccountScreen(dependencies, onBack)
        PersonalHubDestination.ClickTtAccount -> ClickTtAccountScreen(dependencies, onBack)
        PersonalHubDestination.ClickTtBrowser -> ClickTtBrowserScreen(dependencies, onBack)
    }
}

@Composable
private fun PersonalHubTopBar(title: String, onBack: () -> Unit) {
    Row(
        modifier = Modifier.fillMaxWidth(),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        IconButton(onClick = onBack) {
            Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
        }
        Text(title, style = MaterialTheme.typography.h6, fontWeight = FontWeight.SemiBold)
    }
    Spacer(modifier = Modifier.height(8.dp))
}

private fun formatDateTimeUi(iso: String?): String {
    if (iso.isNullOrBlank()) return "–"
    return try {
        val odt = OffsetDateTime.parse(iso)
        odt.format(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm"))
    } catch (_: Exception) {
        iso.take(19).replace('T', ' ')
    }
}

@Composable
private fun PersonalLanguageScreen(dependencies: AppDependencies, onBack: () -> Unit) {
    val languageCode = LocalLanguageCode.current
    fun tr(key: String, fb: String) = MobileStrings.get(languageCode, key, fb)
    Column(
        modifier = Modifier
            .fillMaxSize()
            .verticalScroll(rememberScrollState())
            .padding(PersonalHubPad),
    ) {
        PersonalHubTopBar(tr("settings.personalSettings", "Persönliche Einstellungen"), onBack)
        Card(modifier = Modifier.fillMaxWidth(), elevation = 1.dp) {
            Column(Modifier.padding(16.dp)) {
                Text(tr("settings.language", "Sprache"), fontWeight = FontWeight.SemiBold, style = MaterialTheme.typography.subtitle1)
                Text(
                    tr("settings.languageDescription", "Wähle deine bevorzugte Sprache für die Anwendung"),
                    style = MaterialTheme.typography.body2,
                    modifier = Modifier.padding(top = 8.dp),
                )
                Text(
                    tr("settings.selectLanguage", "Sprache auswählen"),
                    style = MaterialTheme.typography.caption,
                    modifier = Modifier.padding(top = 12.dp),
                )
                MobileStrings.supportedLanguages.forEach { language ->
                    TextButton(
                        onClick = { dependencies.applicationScope.launch { dependencies.languageManager.selectLanguage(language.code) } },
                        modifier = Modifier.fillMaxWidth().heightIn(min = PersonalHubTouchMin),
                    ) {
                        Text(if (language.code == LocalLanguageCode.current) "✓ ${language.label}" else language.label)
                    }
                }
            }
        }
    }
}

@Composable
private fun MyTischtennisAccountScreen(dependencies: AppDependencies, onBack: () -> Unit) {
    val languageCode = LocalLanguageCode.current
    fun tr(key: String, fb: String) = MobileStrings.get(languageCode, key, fb)
    val scope = rememberCoroutineScope()
    var loading by remember { mutableStateOf(true) }
    var account by remember { mutableStateOf<MyTischtennisAccountDto?>(null) }
    var status by remember { mutableStateOf<MyTischtennisStatusDto?>(null) }
    var err by remember { mutableStateOf<String?>(null) }
    var refresh by remember { mutableIntStateOf(0) }
    var showEditor by remember { mutableStateOf(false) }
    var loginMode by remember { mutableStateOf(false) }
    var verifyBusy by remember { mutableStateOf(false) }
    var confirmUnlink by remember { mutableStateOf(false) }
    var infoMsg by remember { mutableStateOf<String?>(null) }

    LaunchedEffect(refresh) {
        loading = true
        err = null
        runCatching {
            val a = dependencies.myTischtennisApi.getAccount()
            val s = dependencies.myTischtennisApi.getStatus()
            account = a.account
            status = s
        }.onFailure { err = it.message }
        loading = false
    }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .verticalScroll(rememberScrollState())
            .padding(PersonalHubPad),
    ) {
        PersonalHubTopBar(tr("myTischtennisAccount.title", "myTischtennis-Account"), onBack)
        infoMsg?.let {
            Text(it, color = MaterialTheme.colors.primary, modifier = Modifier.padding(bottom = 8.dp))
        }
        err?.let { Text(it, color = MaterialTheme.colors.error, modifier = Modifier.padding(bottom = 8.dp)) }
        when {
            loading -> CircularProgressIndicator(modifier = Modifier.padding(top = 24.dp))
            account != null -> {
                val a = account!!
                Card(modifier = Modifier.fillMaxWidth(), elevation = 1.dp) {
                    Column(Modifier.padding(16.dp)) {
                        Text(tr("myTischtennisAccount.linkedAccount", "Verknüpfter Account"), fontWeight = FontWeight.SemiBold)
                        detailRow(tr("myTischtennisAccount.email", "E-Mail"), a.email ?: "–")
                        detailRow(
                            tr("myTischtennisAccount.passwordSaved", "Passwort gespeichert"),
                            if (status?.hasPassword == true) tr("myTischtennisAccount.yes", "Ja") else tr("myTischtennisAccount.no", "Nein"),
                        )
                        if (!a.clubId.isNullOrBlank()) {
                            val clubLine = buildString {
                                append(a.clubName ?: "")
                                append(" (")
                                append(a.clubId)
                                if (!a.fedNickname.isNullOrBlank()) append(" - ").append(a.fedNickname)
                                append(")")
                            }
                            detailRow(tr("myTischtennisAccount.club", "Verein"), clubLine)
                        }
                        a.lastLoginSuccess?.let { detailRow(tr("myTischtennisAccount.lastSuccessfulLogin", "Letzter erfolgreicher Login"), formatDateTimeUi(it)) }
                        a.lastLoginAttempt?.let { detailRow(tr("myTischtennisAccount.lastLoginAttempt", "Letzter Login-Versuch"), formatDateTimeUi(it)) }
                        Spacer(Modifier.height(12.dp))
                        Button(
                            onClick = { loginMode = false; showEditor = true },
                            modifier = Modifier.fillMaxWidth().heightIn(min = PersonalHubTouchMin),
                        ) { Text(tr("myTischtennisAccount.editAccount", "Account bearbeiten")) }
                        OutlinedButton(
                            onClick = {
                                scope.launch {
                                    verifyBusy = true
                                    err = null
                                    runCatching {
                                        dependencies.myTischtennisApi.verifyLogin(null)
                                        refresh++
                                        infoMsg = tr("myTischtennisAccount.loginSuccessful", "Login erfolgreich")
                                    }.onFailure { e ->
                                        if (e is ApiException && e.statusCode == 400) {
                                            loginMode = true
                                            showEditor = true
                                        } else {
                                            err = e.message
                                        }
                                    }
                                    verifyBusy = false
                                }
                            },
                            enabled = !verifyBusy,
                            modifier = Modifier.fillMaxWidth().heightIn(min = PersonalHubTouchMin).padding(top = 8.dp),
                        ) {
                            Text(if (verifyBusy) "…" else tr("myTischtennisAccount.loginAgain", "Erneut einloggen"))
                        }
                        OutlinedButton(
                            onClick = { confirmUnlink = true },
                            modifier = Modifier.fillMaxWidth().heightIn(min = PersonalHubTouchMin).padding(top = 8.dp),
                        ) { Text(tr("myTischtennisAccount.unlinkAccount", "Account trennen")) }
                    }
                }
            }
            else -> {
                Text(tr("myTischtennisAccount.noAccountLinked", "Kein myTischtennis-Account verknüpft."))
                Button(
                    onClick = { loginMode = false; showEditor = true },
                    modifier = Modifier.fillMaxWidth().padding(top = 12.dp).heightIn(min = PersonalHubTouchMin),
                ) { Text(tr("myTischtennisAccount.linkAccount", "Account verknüpfen")) }
            }
        }
        Spacer(Modifier.height(16.dp))
        Card(modifier = Modifier.fillMaxWidth(), elevation = 1.dp) {
            Column(Modifier.padding(16.dp)) {
                Text(tr("myTischtennisAccount.aboutMyTischtennis", "Über myTischtennis"), fontWeight = FontWeight.SemiBold)
                Text(tr("myTischtennisAccount.aboutDescription", ""), modifier = Modifier.padding(top = 6.dp))
                Text("• " + tr("myTischtennisAccount.aboutFeature1", ""), modifier = Modifier.padding(top = 4.dp))
                Text("• " + tr("myTischtennisAccount.aboutFeature2", ""), modifier = Modifier.padding(top = 2.dp))
                Text("• " + tr("myTischtennisAccount.aboutFeature3", ""), modifier = Modifier.padding(top = 2.dp))
                Text(
                    tr("messages.info", "Hinweis") + ": " + tr("myTischtennisAccount.aboutHint", ""),
                    modifier = Modifier.padding(top = 8.dp),
                    style = MaterialTheme.typography.caption,
                )
            }
        }
    }

    if (showEditor) {
        MyTischtennisEditorDialog(
            account = account,
            loginMode = loginMode,
            tr = ::tr,
            onDismiss = { showEditor = false; loginMode = false },
            onSaved = {
                showEditor = false
                loginMode = false
                refresh++
                infoMsg = tr("myTischtennisAccount.accountSaved", "Gespeichert")
            },
            onLoggedIn = {
                showEditor = false
                loginMode = false
                refresh++
                infoMsg = tr("myTischtennisAccount.loginSuccessful", "Login erfolgreich")
            },
            scope = scope,
            api = dependencies.myTischtennisApi,
        )
    }

    if (confirmUnlink) {
        StableAlertDialog(
            onDismissRequest = { confirmUnlink = false },
            title = { Text(tr("myTischtennisAccount.unlinkAccountTitle", "Account trennen")) },
            text = { Text(tr("myTischtennisAccount.unlinkAccountConfirm", "Wirklich trennen?")) },
            confirmButton = {
                TextButton(
                    onClick = {
                        scope.launch {
                            runCatching {
                                dependencies.myTischtennisApi.deleteAccount()
                                account = null
                                status = null
                                confirmUnlink = false
                                refresh++
                                infoMsg = tr("myTischtennisAccount.accountUnlinked", "Getrennt")
                            }.onFailure { err = it.message; confirmUnlink = false }
                        }
                    },
                ) { Text(tr("myTischtennisAccount.unlinkAccount", "Trennen")) }
            },
            dismissButton = {
                TextButton(onClick = { confirmUnlink = false }) { Text(tr("myTischtennisDialog.cancel", "Abbrechen")) }
            },
        )
    }
}

@Composable
private fun detailRow(label: String, value: String) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(vertical = 6.dp),
        horizontalArrangement = Arrangement.SpaceBetween,
    ) {
        Text(label, fontWeight = FontWeight.Medium, modifier = Modifier.weight(0.45f))
        Text(value, modifier = Modifier.weight(0.55f))
    }
}

@Composable
private fun MyTischtennisEditorDialog(
    account: MyTischtennisAccountDto?,
    loginMode: Boolean,
    tr: (String, String) -> String,
    onDismiss: () -> Unit,
    onSaved: () -> Unit,
    onLoggedIn: () -> Unit,
    scope: kotlinx.coroutines.CoroutineScope,
    api: de.tsschulz.tt_tagebuch.shared.api.MyTischtennisApi,
) {
    var email by remember(account?.id, loginMode) { mutableStateOf(account?.email.orEmpty()) }
    var password by remember(account?.id, loginMode) { mutableStateOf("") }
    var savePw by remember(account?.id, loginMode) { mutableStateOf(account?.savePassword == true) }
    var autoRat by remember(account?.id, loginMode) { mutableStateOf(account?.autoUpdateRatings == true) }
    var userPw by remember(account?.id, loginMode) { mutableStateOf("") }
    var err by remember { mutableStateOf<String?>(null) }
    var busy by remember { mutableStateOf(false) }

    StableAlertDialog(
        onDismissRequest = onDismiss,
        title = {
            Text(
                if (loginMode) tr("myTischtennisDialog.login", "Einloggen")
                else if (account != null) tr("myTischtennisDialog.editAccount", "Bearbeiten")
                else tr("myTischtennisDialog.linkAccount", "Verknüpfen"),
            )
        },
        text = {
            Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
                err?.let { Text(it, color = MaterialTheme.colors.error) }
                if (loginMode) {
                    OutlinedTextField(value = email, onValueChange = {}, readOnly = true, label = { Text(tr("myTischtennisDialog.email", "E-Mail")) }, modifier = Modifier.fillMaxWidth())
                    OutlinedTextField(
                        value = password,
                        onValueChange = { password = it },
                        label = { Text(tr("myTischtennisDialog.password", "Passwort")) },
                        visualTransformation = PasswordVisualTransformation(),
                        modifier = Modifier.fillMaxWidth(),
                    )
                } else {
                    OutlinedTextField(value = email, onValueChange = { email = it }, label = { Text(tr("myTischtennisDialog.email", "E-Mail")) }, modifier = Modifier.fillMaxWidth())
                    OutlinedTextField(
                        value = password,
                        onValueChange = { password = it },
                        label = { Text(tr("myTischtennisDialog.password", "Passwort")) },
                        placeholder = { Text(tr("myTischtennisDialog.passwordPlaceholderKeep", "")) },
                        visualTransformation = PasswordVisualTransformation(),
                        modifier = Modifier.fillMaxWidth(),
                    )
                    Row(verticalAlignment = Alignment.CenterVertically) {
                        Switch(checked = savePw, onCheckedChange = { savePw = it })
                        Text(tr("myTischtennisDialog.savePassword", "Passwort speichern"), modifier = Modifier.padding(start = 8.dp))
                    }
                    Row(verticalAlignment = Alignment.CenterVertically) {
                        Switch(checked = autoRat, onCheckedChange = { autoRat = it }, enabled = savePw)
                        Text(tr("myTischtennisDialog.autoUpdateRatings", "Auto-Ratings"), modifier = Modifier.padding(start = 8.dp))
                    }
                    if (password.isNotBlank()) {
                        OutlinedTextField(
                            value = userPw,
                            onValueChange = { userPw = it },
                            label = { Text(tr("myTischtennisDialog.appPassword", "App-Passwort")) },
                            visualTransformation = PasswordVisualTransformation(),
                            modifier = Modifier.fillMaxWidth(),
                        )
                    }
                }
            }
        },
        confirmButton = {
            TextButton(
                enabled = !busy && if (loginMode) {
                    password.isNotBlank()
                } else {
                    email.isNotBlank() && (password.isBlank() || userPw.isNotBlank())
                },
                onClick = {
                    scope.launch {
                        busy = true
                        err = null
                        runCatching {
                            if (loginMode) {
                                api.verifyLogin(password)
                                onLoggedIn()
                            } else {
                                if (password.isNotBlank() && userPw.isBlank()) return@launch
                                api.upsertAccount(
                                    MyTischtennisAccountUpsertBody(
                                        email = email.trim(),
                                        password = password.ifBlank { null },
                                        savePassword = savePw,
                                        autoUpdateRatings = if (savePw) autoRat else false,
                                        userPassword = userPw.ifBlank { null },
                                    ),
                                )
                                onSaved()
                            }
                        }.onFailure { e -> err = e.message }
                        busy = false
                    }
                },
            ) {
                Text(
                    if (loginMode) tr("myTischtennisDialog.login", "Login")
                    else tr("myTischtennisDialog.save", "Speichern"),
                )
            }
        },
        dismissButton = {
            TextButton(onClick = onDismiss, enabled = !busy) { Text(tr("myTischtennisDialog.cancel", "Abbrechen")) }
        },
    )
}

@Composable
private fun ClickTtAccountScreen(dependencies: AppDependencies, onBack: () -> Unit) {
    val languageCode = LocalLanguageCode.current
    fun tr(key: String, fb: String) = MobileStrings.get(languageCode, key, fb)
    fun ct(key: String, fb: String) = MobileStrings.get(languageCode, key, fb) // same; use navigation keys
    val scope = rememberCoroutineScope()
    var loading by remember { mutableStateOf(true) }
    var account by remember { mutableStateOf<ClickTtAccountDto?>(null) }
    var status by remember { mutableStateOf<ClickTtAccountStatusDto?>(null) }
    var err by remember { mutableStateOf<String?>(null) }
    var refresh by remember { mutableIntStateOf(0) }
    var showEditor by remember { mutableStateOf(false) }
    var loginMode by remember { mutableStateOf(false) }
    var verifyBusy by remember { mutableStateOf(false) }
    var confirmDelete by remember { mutableStateOf(false) }
    var infoMsg by remember { mutableStateOf<String?>(null) }

    LaunchedEffect(refresh) {
        loading = true
        err = null
        runCatching {
            val a = dependencies.clickTtAccountApi.getAccount()
            val s = dependencies.clickTtAccountApi.getStatus()
            account = a.account
            status = s
        }.onFailure { err = it.message }
        loading = false
    }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .verticalScroll(rememberScrollState())
            .padding(PersonalHubPad),
    ) {
        PersonalHubTopBar(tr("navigation.clickTtAccount", "HTTV / click-TT-Account"), onBack)
        infoMsg?.let { Text(it, color = MaterialTheme.colors.primary, modifier = Modifier.padding(bottom = 8.dp)) }
        err?.let { Text(it, color = MaterialTheme.colors.error, modifier = Modifier.padding(bottom = 8.dp)) }
        when {
            loading -> CircularProgressIndicator(modifier = Modifier.padding(top = 24.dp))
            account != null -> {
                val a = account!!
                Card(modifier = Modifier.fillMaxWidth(), elevation = 1.dp) {
                    Column(Modifier.padding(16.dp)) {
                        Text(ct("mobile.clickTt.linked", "Verknüpfter Account"), fontWeight = FontWeight.SemiBold)
                        detailRow(ct("mobile.clickTt.username", "Benutzername"), a.username ?: "–")
                        detailRow(
                            ct("mobile.clickTt.passwordSaved", "Passwort gespeichert"),
                            if (status?.hasPassword == true) tr("myTischtennisAccount.yes", "Ja") else tr("myTischtennisAccount.no", "Nein"),
                        )
                        a.lastLoginSuccess?.let { detailRow(ct("mobile.clickTt.lastOk", "Letzter erfolgreicher Login"), formatDateTimeUi(it)) }
                        a.lastLoginAttempt?.let { detailRow(ct("mobile.clickTt.lastTry", "Letzter Login-Versuch"), formatDateTimeUi(it)) }
                        Spacer(Modifier.height(12.dp))
                        Button(
                            onClick = { loginMode = false; showEditor = true },
                            modifier = Modifier.fillMaxWidth().heightIn(min = PersonalHubTouchMin),
                        ) { Text(ct("mobile.clickTt.edit", "Account bearbeiten")) }
                        OutlinedButton(
                            onClick = {
                                scope.launch {
                                    verifyBusy = true
                                    err = null
                                    runCatching {
                                        dependencies.clickTtAccountApi.verifyLogin(null)
                                        refresh++
                                        infoMsg = ct("mobile.clickTt.verifyOk", "Login erfolgreich")
                                    }.onFailure { e ->
                                        if (e is ApiException && e.statusCode == 400) {
                                            loginMode = true
                                            showEditor = true
                                        } else {
                                            err = e.message
                                        }
                                    }
                                    verifyBusy = false
                                }
                            },
                            enabled = !verifyBusy,
                            modifier = Modifier.fillMaxWidth().heightIn(min = PersonalHubTouchMin).padding(top = 8.dp),
                        ) {
                            Text(if (verifyBusy) "…" else ct("mobile.clickTt.verifyAgain", "Login erneut testen"))
                        }
                        OutlinedButton(
                            onClick = { confirmDelete = true },
                            modifier = Modifier.fillMaxWidth().heightIn(min = PersonalHubTouchMin).padding(top = 8.dp),
                        ) { Text(ct("mobile.clickTt.delete", "Account löschen")) }
                    }
                }
            }
            else -> {
                Text(ct("mobile.clickTt.none", "Es ist noch kein HTTV-/click-TT-Account hinterlegt."))
                Button(
                    onClick = { loginMode = false; showEditor = true },
                    modifier = Modifier.fillMaxWidth().padding(top = 12.dp).heightIn(min = PersonalHubTouchMin),
                ) { Text(ct("mobile.clickTt.link", "Account verknüpfen")) }
            }
        }
    }

    if (showEditor) {
        ClickTtEditorDialog(
            account = account,
            loginMode = loginMode,
            tr = ::ct,
            onDismiss = { showEditor = false; loginMode = false },
            onSaved = {
                showEditor = false
                loginMode = false
                refresh++
                infoMsg = ct("mobile.clickTt.saved", "Gespeichert")
            },
            onLoggedIn = {
                showEditor = false
                loginMode = false
                refresh++
                infoMsg = ct("mobile.clickTt.verifyOk", "Login erfolgreich")
            },
            scope = scope,
            api = dependencies.clickTtAccountApi,
        )
    }

    if (confirmDelete) {
        StableAlertDialog(
            onDismissRequest = { confirmDelete = false },
            title = { Text(ct("mobile.clickTt.deleteTitle", "Account löschen")) },
            text = { Text(ct("mobile.clickTt.deleteConfirm", "Wirklich löschen?")) },
            confirmButton = {
                TextButton(
                    onClick = {
                        scope.launch {
                            runCatching {
                                dependencies.clickTtAccountApi.deleteAccount()
                                account = null
                                status = null
                                confirmDelete = false
                                refresh++
                                infoMsg = ct("mobile.clickTt.deleted", "Gelöscht")
                            }.onFailure { err = it.message; confirmDelete = false }
                        }
                    },
                ) { Text(ct("mobile.clickTt.delete", "Löschen")) }
            },
            dismissButton = {
                TextButton(onClick = { confirmDelete = false }) { Text(tr("myTischtennisDialog.cancel", "Abbrechen")) }
            },
        )
    }
}

@Composable
private fun ClickTtEditorDialog(
    account: ClickTtAccountDto?,
    loginMode: Boolean,
    tr: (String, String) -> String,
    onDismiss: () -> Unit,
    onSaved: () -> Unit,
    onLoggedIn: () -> Unit,
    scope: kotlinx.coroutines.CoroutineScope,
    api: de.tsschulz.tt_tagebuch.shared.api.ClickTtAccountApi,
) {
    var username by remember(account?.id, loginMode) { mutableStateOf(account?.username.orEmpty()) }
    var password by remember(account?.id, loginMode) { mutableStateOf("") }
    var savePw by remember(account?.id, loginMode) { mutableStateOf(account?.savePassword == true) }
    var userPw by remember(account?.id, loginMode) { mutableStateOf("") }
    var err by remember { mutableStateOf<String?>(null) }
    var busy by remember { mutableStateOf(false) }

    StableAlertDialog(
        onDismissRequest = onDismiss,
        title = {
            Text(
                if (loginMode) tr("mobile.clickTt.loginTitle", "Login")
                else if (account != null) tr("mobile.clickTt.editTitle", "Account bearbeiten")
                else tr("mobile.clickTt.linkTitle", "Account verknüpfen"),
            )
        },
        text = {
            Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
                err?.let { Text(it, color = MaterialTheme.colors.error) }
                OutlinedTextField(
                    value = username,
                    onValueChange = { if (!loginMode) username = it },
                    readOnly = loginMode,
                    label = { Text(tr("mobile.clickTt.username", "Benutzername")) },
                    modifier = Modifier.fillMaxWidth(),
                )
                OutlinedTextField(
                    value = password,
                    onValueChange = { password = it },
                    label = { Text(tr("mobile.clickTt.password", "Passwort")) },
                    visualTransformation = PasswordVisualTransformation(),
                    modifier = Modifier.fillMaxWidth(),
                )
                if (!loginMode) {
                    Row(verticalAlignment = Alignment.CenterVertically) {
                        Switch(checked = savePw, onCheckedChange = { savePw = it })
                        Text(tr("mobile.clickTt.savePassword", "Passwort speichern"), modifier = Modifier.padding(start = 8.dp))
                    }
                    if (password.isNotBlank()) {
                        OutlinedTextField(
                            value = userPw,
                            onValueChange = { userPw = it },
                            label = { Text(tr("mobile.clickTt.appPassword", "App-Passwort")) },
                            visualTransformation = PasswordVisualTransformation(),
                            modifier = Modifier.fillMaxWidth(),
                        )
                    }
                }
            }
        },
        confirmButton = {
            TextButton(
                enabled = !busy && if (loginMode) {
                    password.isNotBlank()
                } else {
                    username.isNotBlank() && (password.isBlank() || userPw.isNotBlank())
                },
                onClick = {
                    scope.launch {
                        busy = true
                        err = null
                        runCatching {
                            if (loginMode) {
                                api.verifyLogin(password)
                                onLoggedIn()
                            } else {
                                if (password.isNotBlank() && userPw.isBlank()) return@launch
                                api.upsertAccount(
                                    ClickTtAccountUpsertBody(
                                        username = username.trim(),
                                        password = password.ifBlank { null },
                                        savePassword = savePw,
                                        userPassword = userPw.ifBlank { null },
                                    ),
                                )
                                onSaved()
                            }
                        }.onFailure { e -> err = e.message }
                        busy = false
                    }
                },
            ) {
                Text(if (loginMode) tr("mobile.clickTt.testLogin", "Login testen") else tr("myTischtennisDialog.save", "Speichern"))
            }
        },
        dismissButton = {
            TextButton(onClick = onDismiss, enabled = !busy) { Text(tr("myTischtennisDialog.cancel", "Abbrechen")) }
        },
    )
}

private enum class ClickTtPageKind { LeaguePage, ClubInfo, RegionMeetings, DirectUrl, PresetHttvHome, PresetTtdeLogin }

private val clickTtPresetUrls = mapOf(
    ClickTtPageKind.PresetHttvHome to "https://httv.de",
    ClickTtPageKind.PresetTtdeLogin to "https://ttde-id.liga.nu/oauth2/authz/ttde?scope=nuLiga&response_type=code&redirect_uri=https%3A%2F%2Fhttv.click-tt.de%2Fcgi-bin%2FWebObjects%2FnuLigaTTDE.woa%2Fwa%2FoAuthLogin&state=nonce%3DVF6WbXUOvTjpsGq9zoZ6oxTH7625JEGH&client_id=XtVpGjXKAhz3BZuu",
)

private fun encodeQuery(s: String): String = URLEncoder.encode(s, StandardCharsets.UTF_8.name())

private fun buildClickTtProxyUrl(
    backendBase: String,
    sid: String,
    kind: ClickTtPageKind,
    association: String,
    championship: String,
    clubId: String,
    directUrl: String,
): String {
    val base = backendBase.trimEnd('/')
    val sb = StringBuilder(base).append("/api/clicktt/proxy?sid=").append(encodeQuery(sid))
    when (kind) {
        ClickTtPageKind.DirectUrl -> {
            sb.append("&url=").append(encodeQuery(directUrl.trim()))
        }
        ClickTtPageKind.PresetHttvHome, ClickTtPageKind.PresetTtdeLogin -> {
            val u = clickTtPresetUrls[kind]!!
            sb.append("&url=").append(encodeQuery(u))
        }
        ClickTtPageKind.LeaguePage -> {
            sb.append("&type=leaguePage")
            sb.append("&association=").append(encodeQuery(association))
            sb.append("&championship=").append(encodeQuery(championship))
        }
        ClickTtPageKind.RegionMeetings -> {
            sb.append("&type=regionMeetings")
            sb.append("&association=").append(encodeQuery(association))
            sb.append("&championship=").append(encodeQuery(championship))
        }
        ClickTtPageKind.ClubInfo -> {
            sb.append("&type=clubInfo")
            sb.append("&association=").append(encodeQuery(association))
            sb.append("&clubId=").append(encodeQuery(clubId.trim()))
        }
    }
    return sb.toString()
}

@SuppressLint("SetJavaScriptEnabled")
@Composable
private fun ClickTtBrowserScreen(dependencies: AppDependencies, onBack: () -> Unit) {
    val languageCode = LocalLanguageCode.current
    fun tr(key: String, fb: String) = MobileStrings.get(languageCode, key, fb)
    var kind by remember { mutableStateOf(ClickTtPageKind.LeaguePage) }
    var assocMenu by remember { mutableStateOf(false) }
    var pageMenu by remember { mutableStateOf(false) }
    var association by remember { mutableStateOf("HeTTV") }
    var championship by remember { mutableStateOf("HTTV 25/26") }
    var clubId by remember { mutableStateOf("") }
    var directUrl by remember { mutableStateOf("") }
    var sid by remember { mutableStateOf(UUID.randomUUID().toString()) }
    var loadedUrl by remember { mutableStateOf<String?>(null) }

    val assocs = listOf("HeTTV", "RTTV", "WTTV", "TTVNw")
    fun canLoad(): Boolean = when (kind) {
        ClickTtPageKind.DirectUrl -> directUrl.isNotBlank()
        ClickTtPageKind.ClubInfo -> clubId.isNotBlank()
        else -> true
    }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(PersonalHubPad),
    ) {
        PersonalHubTopBar(tr("navigation.clickTtBrowser", "HTTV / click-TT"), onBack)
        Text(
            tr("mobile.clickTtBrowser.hint", "Lade click-TT-Seiten über den Server-Proxy. JavaScript ist aktiviert."),
            style = MaterialTheme.typography.caption,
            modifier = Modifier.padding(bottom = 8.dp),
        )
        Text(tr("mobile.clickTtBrowser.pageType", "Seitentyp"), style = MaterialTheme.typography.caption)
        Box {
            TextButton(onClick = { pageMenu = true }, modifier = Modifier.fillMaxWidth()) {
                Text(
                    when (kind) {
                        ClickTtPageKind.LeaguePage -> "Ligenübersicht"
                        ClickTtPageKind.ClubInfo -> "Vereinsinfo"
                        ClickTtPageKind.RegionMeetings -> "Regionsspielplan"
                        ClickTtPageKind.DirectUrl -> "Direkte URL"
                        ClickTtPageKind.PresetHttvHome -> "HTTV Einstieg"
                        ClickTtPageKind.PresetTtdeLogin -> "TTDE Login"
                    },
                )
            }
            DropdownMenu(expanded = pageMenu, onDismissRequest = { pageMenu = false }) {
                DropdownMenuItem(onClick = { kind = ClickTtPageKind.LeaguePage; pageMenu = false }) { Text("Ligenübersicht") }
                DropdownMenuItem(onClick = { kind = ClickTtPageKind.ClubInfo; pageMenu = false }) { Text("Vereinsinfo") }
                DropdownMenuItem(onClick = { kind = ClickTtPageKind.RegionMeetings; pageMenu = false }) { Text("Regionsspielplan") }
                DropdownMenuItem(onClick = { kind = ClickTtPageKind.DirectUrl; pageMenu = false }) { Text("Direkte URL") }
                DropdownMenuItem(onClick = { kind = ClickTtPageKind.PresetHttvHome; pageMenu = false }) { Text("HTTV Einstieg") }
                DropdownMenuItem(onClick = { kind = ClickTtPageKind.PresetTtdeLogin; pageMenu = false }) { Text("TTDE Login") }
            }
        }
        if (kind == ClickTtPageKind.LeaguePage || kind == ClickTtPageKind.ClubInfo || kind == ClickTtPageKind.RegionMeetings) {
            Text(tr("mobile.clickTtBrowser.association", "Verband"), style = MaterialTheme.typography.caption, modifier = Modifier.padding(top = 8.dp))
            Box {
                TextButton(onClick = { assocMenu = true }) { Text(association) }
                DropdownMenu(expanded = assocMenu, onDismissRequest = { assocMenu = false }) {
                    assocs.forEach { a ->
                        DropdownMenuItem(onClick = { association = a; assocMenu = false }) { Text(a) }
                    }
                }
            }
        }
        if (kind == ClickTtPageKind.LeaguePage || kind == ClickTtPageKind.RegionMeetings) {
            OutlinedTextField(
                value = championship,
                onValueChange = { championship = it },
                label = { Text(tr("mobile.clickTtBrowser.championship", "Championship / Saison")) },
                modifier = Modifier.fillMaxWidth().padding(top = 4.dp),
                singleLine = true,
            )
        }
        if (kind == ClickTtPageKind.ClubInfo) {
            OutlinedTextField(
                value = clubId,
                onValueChange = { clubId = it },
                label = { Text(tr("mobile.clickTtBrowser.clubId", "Vereins-ID")) },
                modifier = Modifier.fillMaxWidth().padding(top = 4.dp),
                singleLine = true,
            )
        }
        if (kind == ClickTtPageKind.DirectUrl) {
            OutlinedTextField(
                value = directUrl,
                onValueChange = { directUrl = it },
                label = { Text("URL") },
                modifier = Modifier.fillMaxWidth().padding(top = 4.dp),
                singleLine = false,
                minLines = 2,
            )
        }
        Row(
            modifier = Modifier
                .fillMaxWidth()
                .padding(top = 8.dp),
            horizontalArrangement = Arrangement.spacedBy(8.dp),
        ) {
            Button(
                onClick = {
                    if (!canLoad()) return@Button
                    sid = UUID.randomUUID().toString()
                    loadedUrl = buildClickTtProxyUrl(
                        dependencies.apiConfig.baseUrl,
                        sid,
                        kind,
                        association,
                        championship,
                        clubId,
                        directUrl,
                    )
                },
                enabled = canLoad(),
                modifier = Modifier.weight(1f).heightIn(min = PersonalHubTouchMin),
            ) { Text(tr("mobile.clickTtBrowser.load", "Laden")) }
            OutlinedButton(
                onClick = { loadedUrl = null },
                modifier = Modifier.heightIn(min = PersonalHubTouchMin),
            ) { Text(tr("mobile.clickTtBrowser.clear", "Leeren")) }
        }
        Spacer(Modifier.height(8.dp))
        val u = loadedUrl
        if (u != null) {
            AndroidView(
                factory = { ctx ->
                    WebView(ctx).apply {
                        layoutParams = ViewGroup.LayoutParams(
                            ViewGroup.LayoutParams.MATCH_PARENT,
                            ViewGroup.LayoutParams.MATCH_PARENT,
                        )
                        settings.javaScriptEnabled = true
                        settings.domStorageEnabled = true
                        settings.cacheMode = WebSettings.LOAD_DEFAULT
                        webViewClient = WebViewClient()
                        webChromeClient = WebChromeClient()
                        loadUrl(u)
                    }
                },
                update = { w ->
                    if (w.url != u) w.loadUrl(u)
                },
                modifier = Modifier
                    .fillMaxWidth()
                    .weight(1f),
            )
        } else {
            Text(
                tr("mobile.clickTtBrowser.placeholder", "Seite laden …"),
                modifier = Modifier
                    .fillMaxWidth()
                    .weight(1f)
                    .padding(top = 16.dp),
            )
        }
    }
}
