package com.fmdxconnector

import android.Manifest
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ChevronLeft
import androidx.compose.material.icons.filled.ChevronRight
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.Public
import androidx.compose.material.icons.filled.Visibility
import androidx.compose.material.icons.filled.VisibilityOff
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ProvideTextStyle
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.content.ContextCompat
import androidx.core.view.WindowCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.media3.common.util.UnstableApi
import com.fmdxconnector.audio.AudioWebSocketPlayer
import com.fmdxconnector.ui.theme.FMDXConnectorTheme
import androidx.compose.ui.text.style.TextOverflow
import kotlinx.coroutines.launch
import androidx.compose.ui.text.style.TextAlign

// Insets
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.layout.systemBars
import androidx.compose.runtime.snapshots.SnapshotStateMap

class MainActivity : ComponentActivity() {

    private val viewModel: MainViewModel by viewModels()
    private var isReceiverRegistered = false
    private lateinit var sharedPreferences: SharedPreferences

    // → Ausgelagerte GPS/WebView-Funktionalität
    private lateinit var gpsHelper: GpsWebViewHelper

    private var logCollectorStarted = false

    // Logging zentral
    fun addAppLog(message: String, level: LogLevel = LogLevel.INFO) {
        LogCenter.log(message, level)
    }

    private val statusUpdateReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            intent ?: return
            val socketName = intent.getStringExtra("socket_name") ?: return
            val isConnected = intent.getBooleanExtra("is_connected", false)
            val hostId = intent.getIntExtra("host_id", 0)
            Log.d("MainActivity", "Status Update: $socketName = $isConnected for host $hostId")
            viewModel.updateLedState(socketName, isConnected, hostId)
        }
    }

    private val requestPermissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) { /* no-op */ }

    private fun askNotificationPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            val granted = ContextCompat.checkSelfPermission(
                this, Manifest.permission.POST_NOTIFICATIONS
            ) == PackageManager.PERMISSION_GRANTED
            if (!granted) requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
        }
    }

    override fun onStart() {
        super.onStart()
        if (!isReceiverRegistered) {
            val intentFilter = IntentFilter(NetworkService.ACTION_STATUS_UPDATE)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                registerReceiver(statusUpdateReceiver, intentFilter, Context.RECEIVER_EXPORTED)
            } else {
                @Suppress("UnspecifiedRegisterReceiverFlag")
                registerReceiver(statusUpdateReceiver, intentFilter)
            }
            isReceiverRegistered = true
            Log.d("MainActivity", "Status Update Receiver registered")
        }
    }

    override fun onStop() {
        super.onStop()
        if (isReceiverRegistered) {
            unregisterReceiver(statusUpdateReceiver)
            isReceiverRegistered = false
            Log.d("MainActivity", "Status Update Receiver unregistered")
        }
    }

    @androidx.annotation.OptIn(UnstableApi::class)
    override fun onDestroy() {
        // Sicherheit: WebSocket/Timer/WebView & Audio beenden
        if (this::gpsHelper.isInitialized) gpsHelper.stop()
        AudioWebSocketPlayer.stop()
        super.onDestroy()
    }

    @androidx.annotation.OptIn(UnstableApi::class)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d("MainActivity", "onCreate called")

        // Lock screen orientation to portrait
        requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT

        askNotificationPermission()
        sharedPreferences = getSharedPreferences("fmdx_prefs", Context.MODE_PRIVATE)

        val showAboutState = mutableStateOf(false)
        val showExitState = mutableStateOf(false)

        // Systemleisten klassisch behandeln (vor setContent)
        WindowCompat.setDecorFitsSystemWindows(window, true)

        // Update-Check
        lifecycleScope.launch {
            UpdateChecker.checkAndPrompt(
                activity = this@MainActivity,
                currentVersion = getAppVersion(this@MainActivity)
            )
        }

        // GPS/WebView-Helper initialisieren
        gpsHelper = GpsWebViewHelper(
            context = applicationContext,
            onLog = { msg -> LogCenter.info(msg) },
            onGps = { _, _, _, _ -> }
        )

        // LogFlow nur EINMAL starten
        if (!logCollectorStarted) {
            logCollectorStarted = true

            lifecycleScope.launch {
                repeatOnLifecycle(Lifecycle.State.STARTED) {
                    MainViewModel.logFlow.collect { (message, level) ->
                        val logLevel = when (level) {
                            "ERROR" -> LogLevel.ERROR
                            "WARNING" -> LogLevel.WARNING
                            "SUCCESS" -> LogLevel.SUCCESS
                            else -> LogLevel.INFO
                        }
                        LogCenter.log(message, logLevel)
                    }
                }
            }
        }

        setContent {
            FMDXConnectorTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    val mainUiState = viewModel.uiState.collectAsStateWithLifecycle()

                    if (showAboutState.value) {
                        AboutDialog(onDismiss = { showAboutState.value = false })
                    }
                    if (showExitState.value) {
                        ExitDialog(
                            onDismiss = { showExitState.value = false },
                            onExit = {
                                viewModel.disconnectAll()
                                gpsHelper.stop()
                                AudioWebSocketPlayer.stop()
                                finishAndRemoveTask()
                                System.exit(0)
                            }
                        )
                    }

                    MainScreen(
                        context = this@MainActivity,
                        uiState = mainUiState.value,
                        onAddHost = { viewModel.addHost() },
                        onConnectQuick = { host ->
                            val state = viewModel.uiState.value
                            val isActiveHost = state.activeHostId == host.id

                            if (isActiveHost) {
                                // 👉 IMMER: harten Disconnect machen, egal ob rot/gelb/grün
                                viewModel.disconnectAll()
                                gpsHelper.stop()
                                AudioWebSocketPlayer.stop()
                            } else {
                                // 👉 Neuen Connect starten
                                gpsHelper.stop()
                                gpsHelper.start(host.address, watchMillis = 60_000L)
                                viewModel.connectToHost(host)
                            }
                        },
                        onAddressChanged = { id, addr -> viewModel.onAddressChanged(id, addr) },
                        onAdminPasswordChanged = { id, pwd -> viewModel.onAdminPasswordChanged(id, pwd) },
                        onDeleteHost = { id -> viewModel.deleteHost(id) },
                        onServerNameChanged = { id, name -> viewModel.onServerNameChanged(id, name) },
                        onMinimize = { moveTaskToBack(true) },
                        onAbout = { showAboutState.value = true },
                        onExit = { showExitState.value = true }
                    )
                }
            }
        }
    }

    // ---------------- UI ----------------

    @androidx.annotation.OptIn(UnstableApi::class)
    @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
    @Composable
    fun MainScreen(
        context: Context,
        uiState: MainUiState,
        onAddHost: () -> Unit,
        onConnectQuick: (HostState) -> Unit,
        onAddressChanged: (Int, String) -> Unit,
        onAdminPasswordChanged: (Int, String) -> Unit,
        onDeleteHost: (Int) -> Unit,
        onServerNameChanged: (Int, String) -> Unit,
        onMinimize: () -> Unit,
        onAbout: () -> Unit,
        onExit: () -> Unit
    ) {
        val menuExpanded = remember { mutableStateOf(false) }
        val focusManager = LocalFocusManager.current
        val rootScope = rememberCoroutineScope()

        val density = LocalDensity.current
        val layoutDir = LocalLayoutDirection.current
        val statusTop = with(density) { WindowInsets.statusBars.getTop(this).toDp() }
        val navBottom = with(density) { WindowInsets.navigationBars.getBottom(this).toDp() }
        val sysLeft = with(density) { WindowInsets.systemBars.getLeft(this, layoutDir).toDp() }
        val sysRight = with(density) { WindowInsets.systemBars.getRight(this, layoutDir).toDp() }

        // State für Audio-Play/Stop Button
        val isAudioPlaying = remember { mutableStateOf(false) }
        // State für World-Map-Overlay
        val showServersMap = remember { mutableStateOf(false) }
        // Merkt sich, von welchem Host aus wir kopieren wollen
        val pendingCloneFromHost = remember { mutableStateOf<HostState?>(null) }

        LaunchedEffect(uiState.textConnected, uiState.pluginsConnected) {
            val connected = uiState.textConnected || uiState.pluginsConnected
            val activeHost = uiState.hosts.firstOrNull { it.id == uiState.activeHostId }

            if (connected && !isAudioPlaying.value) {
                activeHost?.let {
                    AudioWebSocketPlayer.start(context.applicationContext, it.address)
                    isAudioPlaying.value = true
                }
            } else if (!connected && isAudioPlaying.value) {
                AudioWebSocketPlayer.stop()
                isAudioPlaying.value = false
            }
        }

        Scaffold(
            contentWindowInsets = WindowInsets(0),
            topBar = {
                Box(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(top = statusTop, start = sysLeft, end = sysRight)
                        .height(75.dp)
                        .background(Color(0xFF64B5F6)),
                    contentAlignment = Alignment.Center
                ) {
                    Row(
                        modifier = Modifier
                            .fillMaxWidth()
                            .height(75.dp)
                            .padding(horizontal = 16.dp),
                        verticalAlignment = Alignment.CenterVertically,
                        horizontalArrangement = Arrangement.SpaceBetween
                    ) {
                        // Linke Seite: Titel + Untertitel
                        Column {
                            Text(
                                text = "FMDX Connector",
                                fontSize = 20.sp,
                                fontWeight = FontWeight.Bold,
                                color = Color.White
                            )
                            val sub = uiState.hosts.firstOrNull { it.id == uiState.activeHostId }?.address
                                ?.takeIf { it.isNotBlank() }
                                ?.let { addr ->
                                    try {
                                        val parsed = if (addr.contains("://")) Uri.parse(addr) else Uri.parse("http://$addr")
                                        parsed.host ?: run {
                                            if (addr.startsWith("[")) addr.substringAfter("[").substringBefore("]")
                                            else addr.substringBefore(':')
                                        }
                                    } catch (_: Exception) {
                                        if (addr.startsWith("[")) addr.substringAfter("[").substringBefore("]")
                                        else addr.substringBefore(':')
                                    }
                                } ?: "No connection"
                            Text(
                                text = sub,
                                fontSize = 14.sp,
                                color = Color.White.copy(alpha = 0.85f)
                            )
                        }

                        // Rechte Seite: Globe + Play/Stop + Menü
                        Row(
                            verticalAlignment = Alignment.CenterVertically,
                            horizontalArrangement = Arrangement.spacedBy(0.dp)
                        ) {
                            // 🌍 Globe: servers.fmdx.org ein-/ausblenden
                            IconButton(
                                onClick = { showServersMap.value = !showServersMap.value },
                                modifier = Modifier.size(48.dp)
                            ) {
                                Icon(
                                    imageVector = Icons.Filled.Public,
                                    contentDescription = if (showServersMap.value) "Hide servers map" else "Show servers map",
                                    tint = Color.White,
                                    modifier = Modifier.size(28.dp)
                                )
                            }

                            // ▶️ / ⏹ Play/Stop – größer
                            IconButton(
                                onClick = {
                                    val activeHost =
                                        uiState.hosts.firstOrNull { it.id == uiState.activeHostId }
                                            ?: uiState.hosts.firstOrNull()

                                    val connected = uiState.textConnected || uiState.pluginsConnected

                                    if (isAudioPlaying.value) {
                                        AudioWebSocketPlayer.stop()
                                        isAudioPlaying.value = false
                                    } else {
                                        if (!connected && activeHost != null) {
                                            onConnectQuick(activeHost)
                                        } else if (connected && activeHost != null) {
                                            AudioWebSocketPlayer.start(context.applicationContext, activeHost.address)
                                            isAudioPlaying.value = true
                                        }
                                    }
                                },
                                modifier = Modifier.size(56.dp)
                            ) {
                                if (isAudioPlaying.value) {
                                    StopIconWhite(modifier = Modifier.size(38.dp))
                                } else {
                                    PlayIconWhite(modifier = Modifier.size(38.dp))
                                }
                            }

                            // Menü ganz rechts
                            Box {
                                IconButton(
                                    onClick = { menuExpanded.value = !menuExpanded.value },
                                    modifier = Modifier.size(40.dp)
                                ) {
                                    Icon(
                                        imageVector = Icons.Default.MoreVert,
                                        contentDescription = "Menu",
                                        tint = Color.White,
                                        modifier = Modifier.size(28.dp)
                                    )
                                }
                                DropdownMenu(
                                    expanded = menuExpanded.value,
                                    onDismissRequest = { menuExpanded.value = false }
                                ) {
                                    DropdownMenuItem(text = { Text("About") }, onClick = {
                                        menuExpanded.value = false; onAbout()
                                    })
                                    DropdownMenuItem(text = { Text("Minimize") }, onClick = {
                                        menuExpanded.value = false; onMinimize()
                                    })
                                    DropdownMenuItem(text = { Text("Exit") }, onClick = {
                                        menuExpanded.value = false; onExit()
                                    })
                                }
                            }
                        }
                    }
                }
            }
        ) { innerPadding ->

            // Äußere Box: System-Insets + Toolbar berücksichtigen
            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .padding(innerPadding)
                    .padding(start = sysLeft, end = sysRight, bottom = navBottom)
            ) {

                val pageCount = uiState.hosts.size
                val pagerState = rememberPagerState(initialPage = 0, pageCount = { pageCount })

                // Normale App-UI mit 16.dp horizontalem Rand
                Column(
                    modifier = Modifier
                        .fillMaxSize()
                        .padding(horizontal = 16.dp)
                ) {
                    Spacer(Modifier.height(16.dp))

                    val coroutineScope = rememberCoroutineScope()

                    val activeHost = uiState.hosts.firstOrNull { it.id == uiState.activeHostId }
                    val isConnected = activeHost != null && (uiState.textConnected || uiState.pluginsConnected)
                    val previousHostCount = remember { mutableStateOf(uiState.hosts.size) }

                    // Wenn ein Host neu hinzugefügt wurde, ggf. klonen & zu neuer Seite springen
                    LaunchedEffect(uiState.hosts.size) {
                        if (uiState.hosts.size > previousHostCount.value) {
                            val src = pendingCloneFromHost.value
                            val newHost = uiState.hosts.lastOrNull()
                            if (src != null && newHost != null) {
                                // Adresse + Passwort klonen
                                onAddressChanged(newHost.id, src.address)
                                onAdminPasswordChanged(newHost.id, src.adminPassword)
                                // Servernamen beim Klonen übernehmen
                                if (src != null && newHost != null) {
                                    onAddressChanged(newHost.id, src.address)
                                    onAdminPasswordChanged(newHost.id, src.adminPassword)
                                    onServerNameChanged(newHost.id, src.serverName)   // 👈 NEU
                                    pendingCloneFromHost.value = null
                                }

                                pendingCloneFromHost.value = null
                            }
                            val newHostPage = (uiState.hosts.size - 1).coerceAtLeast(0)
                            try { pagerState.animateScrollToPage(newHostPage) } catch (_: Exception) {}
                        }
                        previousHostCount.value = uiState.hosts.size
                    }

                    // Bereich unter der Toolbar: Logs + Serverkarten
                    Box(
                        modifier = Modifier
                            .fillMaxWidth()
                            .weight(1f)
                    ) {
                        Column(
                            modifier = Modifier.fillMaxSize()
                        ) {
                            LoggingPanel(
                                modifier = Modifier
                                    .fillMaxWidth()
                                    .weight(1f),
                                title = "System Logs"
                            )
                            Spacer(Modifier.height(12.dp))

                            Row(
                                modifier = Modifier.fillMaxWidth(),
                                verticalAlignment = Alignment.CenterVertically,
                                horizontalArrangement = Arrangement.SpaceBetween
                            ) {
                                Text(
                                    "Server",
                                    style = MaterialTheme.typography.titleMedium,
                                    fontWeight = FontWeight.SemiBold
                                )

                                val showLeft = pagerState.currentPage > 0
                                val showRight = pagerState.currentPage < maxOf(pagerState.pageCount - 1, 0)

                                val enabledLeft = showLeft && !isConnected
                                val enabledRight = showRight && !isConnected
                                val canModifyHosts = !isConnected

                                val buttonSize = 40.dp
                                val buttonShape = RoundedCornerShape(8.dp)

                                Row(verticalAlignment = Alignment.CenterVertically) {
                                    // Pfeil links
                                    Button(
                                        onClick = {
                                            coroutineScope.launch {
                                                pagerState.animateScrollToPage(
                                                    (pagerState.currentPage - 1).coerceAtLeast(0)
                                                )
                                            }
                                        },
                                        enabled = enabledLeft,
                                        shape = buttonShape,
                                        colors = ButtonDefaults.buttonColors(
                                            containerColor = Color(0xFF64B5F6),
                                            contentColor = Color.White
                                        ),
                                        modifier = Modifier.size(buttonSize),
                                        contentPadding = PaddingValues(0.dp)
                                    ) {
                                        Icon(
                                            imageVector = Icons.Filled.ChevronLeft,
                                            contentDescription = "Scroll Left"
                                        )
                                    }

                                    Spacer(Modifier.width(8.dp))

                                    // ➕ Add / Clone Button in der Mitte
                                    Button(
                                        onClick = {
                                            if (!canModifyHosts || pagerState.currentPage != 0) return@Button

                                            val currentHost = uiState.hosts.getOrNull(pagerState.currentPage)
                                            pendingCloneFromHost.value = currentHost
                                            onAddHost()
                                        },
                                        enabled = canModifyHosts && pagerState.currentPage == 0,
                                        shape = buttonShape,
                                        colors = ButtonDefaults.buttonColors(
                                            containerColor = if (pagerState.currentPage == 0) Color(0xFF64B5F6) else Color(0xFF64B5F6).copy(alpha = 0.3f),
                                            contentColor = Color.White.copy(alpha = if (pagerState.currentPage == 0) 1f else 0.5f)
                                        ),
                                        modifier = Modifier.size(buttonSize),
                                        contentPadding = PaddingValues(0.dp)
                                    ) {
                                        Text("+", fontWeight = FontWeight.Bold, fontSize = 20.sp)
                                    }

                                    Spacer(Modifier.width(8.dp))

                                    // Pfeil rechts
                                    Button(
                                        onClick = {
                                            coroutineScope.launch {
                                                pagerState.animateScrollToPage(
                                                    (pagerState.currentPage + 1).coerceAtMost(
                                                        maxOf(pagerState.pageCount - 1, 0)
                                                    )
                                                )
                                            }
                                        },
                                        enabled = enabledRight,
                                        shape = buttonShape,
                                        colors = ButtonDefaults.buttonColors(
                                            containerColor = Color(0xFF64B5F6),
                                            contentColor = Color.White
                                        ),
                                        modifier = Modifier.size(buttonSize),
                                        contentPadding = PaddingValues(0.dp)
                                    ) {
                                        Icon(
                                            imageVector = Icons.Filled.ChevronRight,
                                            contentDescription = "Scroll Right"
                                        )
                                    }
                                }
                            }

                            Spacer(Modifier.height(8.dp))

                            HorizontalPager(
                                state = pagerState,
                                modifier = Modifier
                                    .fillMaxWidth()
                                    .height(250.dp),
                                key = { index ->
                                    if (index < uiState.hosts.size) uiState.hosts[index].id else -9999
                                },
                                userScrollEnabled = !isConnected
                            ) { page ->
                                if (page < uiState.hosts.size) {
                                    val host = uiState.hosts[page]

                                    // Erste Box (page == 0) darf nicht gelöscht werden
                                    val canDelete = page != 0

                                    ServerItem(
                                        index = page,                    // 0-basiert → #0, #1, ...
                                        host = host,
                                        serverName = host.serverName,
                                        isActive = uiState.activeHostId == host.id,
                                        textConnected = uiState.textConnected,
                                        pluginsConnected = uiState.pluginsConnected,
                                        canDelete = page != 0,           
                                        onConnectQuick = { hostState ->
                                            focusManager.clearFocus()
                                            onConnectQuick(hostState)
                                        },
                                        onAddressChanged = { newAddr -> onAddressChanged(host.id, newAddr) },
                                        onAdminPasswordChanged = { newPwd -> onAdminPasswordChanged(host.id, newPwd) },
                                        onServerNameChanged = { newName -> onServerNameChanged(host.id, newName) },
                                        onDeleteHost = { onDeleteHost(host.id) }
                                    )
                                }
                            }

                            Spacer(Modifier.height(16.dp))
                        }
                    }

                    Spacer(Modifier.height(16.dp))
                }

                // Overlay-WebView: vollflächig, ohne inneren Rand
                ServersMapOverlay(
                    modifier = Modifier.fillMaxSize(),
                    visible = showServersMap.value,
                    onServerSelected = { rawUrl, name ->

                        showServersMap.value = false

                        // --- URL bereinigen ---
                        val cleanUrl = rawUrl
                            .removeSuffix("/?")
                            .removeSuffix("?")
                            .removeSuffix("/")   // optional: entfernt reinen Slash am Ende

                        // Immer die erste Serverbox (#0) verwenden
                        val targetHost = uiState.hosts.firstOrNull()

                        if (targetHost != null) {

                            val finalName = if (name.isNotBlank()) name else cleanUrl
                            onServerNameChanged(targetHost.id, finalName)

                            // Admin-Passwort von #0 beim Connect aus dem WebView immer leeren
                            onAdminPasswordChanged(targetHost.id, "")

                            // neue URL in Serverbox #0 schreiben
                            onAddressChanged(targetHost.id, cleanUrl)

                            val updatedHost = targetHost.copy(address = cleanUrl)

                            // 🔥 Harter Reconnect: alte Verbindungen beenden, neuen Host verbinden
                            viewModel.disconnectAll()
                            gpsHelper.stop()
                            AudioWebSocketPlayer.stop()

                            gpsHelper.start(updatedHost.address, watchMillis = 60_000L)
                            viewModel.connectToHost(updatedHost)

                            // 👉 Pager auf Seite 0 scrollen, damit Box #0 sichtbar ist
                            rootScope.launch {
                                try {
                                    pagerState.animateScrollToPage(0)
                                } catch (_: Exception) {
                                    // zur Sicherheit ignorieren
                                }
                            }

                        } else {
                            LogCenter.log("No host slots available to connect to $cleanUrl", LogLevel.WARNING)
                        }
                    }
                )
            }
        }
    }

    // ---- kleine UI-Helfer, die in der Activity bleiben dürfen ----

    @Composable
    fun CompactOutlinedTextField(
        value: String,
        onValueChange: (String) -> Unit,
        modifier: Modifier = Modifier,
        singleLine: Boolean = true,
        minHeight: Dp = 40.dp,
        label: (@Composable () -> Unit)? = null
    ) {
        val shape = RoundedCornerShape(8.dp)
        val border = androidx.compose.foundation.BorderStroke(1.dp, MaterialTheme.colorScheme.outline)

        BasicTextField(
            value = value,
            onValueChange = onValueChange,
            singleLine = singleLine,
            textStyle = MaterialTheme.typography.bodySmall.copy(
                color = MaterialTheme.colorScheme.onSurface
            ),
            cursorBrush = SolidColor(MaterialTheme.colorScheme.primary),
            modifier = modifier
                .heightIn(min = minHeight)
                .background(MaterialTheme.colorScheme.surface, shape)
                .border(border, shape)
                .padding(horizontal = 12.dp, vertical = 8.dp),
            decorationBox = { inner ->
                Column(Modifier.fillMaxWidth()) {
                    if (label != null) {
                        ProvideTextStyle(MaterialTheme.typography.labelSmall) {
                            androidx.compose.runtime.CompositionLocalProvider(
                                LocalContentColor provides MaterialTheme.colorScheme.onSurfaceVariant
                            ) { label() }
                        }
                        Spacer(Modifier.height(2.dp))
                    }
                    inner()
                }
            }
        )
    }

    @Composable
    fun ServerItem(
        index: Int,
        host: HostState,
        serverName: String?,
        isActive: Boolean,
        textConnected: Boolean,
        pluginsConnected: Boolean,
        canDelete: Boolean,
        onConnectQuick: (HostState) -> Unit,
        onAddressChanged: (String) -> Unit,
        onAdminPasswordChanged: (String) -> Unit,
        onServerNameChanged: (String) -> Unit,   // 👈 NEU
        onDeleteHost: () -> Unit
    ) {
        val focusManager = LocalFocusManager.current
        val connected = isActive || textConnected || pluginsConnected
        var passwordVisible by remember { mutableStateOf(false) }

        Card(
            modifier = Modifier
                .fillMaxWidth()
                .padding(vertical = 4.dp)
        ) {
            Column(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(12.dp)
            ) {
                Row(
                    verticalAlignment = Alignment.CenterVertically,
                    modifier = Modifier.fillMaxWidth()
                ) {
                    // Links: Nummer (#0 / MEM #...)
                    Box(
                        modifier = Modifier.weight(0.15f),
                        contentAlignment = Alignment.CenterStart
                    ) {
                        Text(
                            text = if (index == 0) "#0" else "#$index",
                            fontSize = 18.sp,
                            fontWeight = FontWeight.Bold,
                            color = Color.White,
                            maxLines = 1,
                            softWrap = false
                        )
                    }

                    // Mitte: Servername (max 50% Breite, 2 Zeilen, feste Höhe)
                    Box(
                        modifier = Modifier
                            .weight(0.5f)
                            .padding(horizontal = 8.dp)
                            .height(36.dp),     // Höhe für exakt 2 Zeilen
                        contentAlignment = Alignment.Center
                    ) {
                        Text(
                            text = serverName ?: "",
                            fontSize = 13.sp,
                            fontWeight = FontWeight.Medium,
                            color = Color.White.copy(alpha = 0.3f),
                            textAlign = TextAlign.Center,
                            maxLines = 2,
                            overflow = TextOverflow.Clip,
                            lineHeight = 13.sp,
                            softWrap = true
                        )
                    }

                    // Rechts: X (Box 0 löscht Felder, andere Boxen löschen den Host)
                    Box(
                        modifier = Modifier.weight(0.15f),
                        contentAlignment = Alignment.CenterEnd
                    ) {
                        IconButton(
                            onClick = {
                                if (!connected) {
                                    if (index == 0) {
                                        // → Box #0: Werte leeren
                                        onAddressChanged("")
                                        onAdminPasswordChanged("")
                                        onServerNameChanged("")
                                    } else {
                                        // → Normale Boxen: löschen
                                        onDeleteHost()
                                    }
                                }
                            },
                            enabled = !connected,
                            modifier = Modifier.size(24.dp)
                        ) {
                            Icon(
                                imageVector = Icons.Default.Close,
                                contentDescription = if (index == 0) "Clear Box" else "Delete Server",
                                tint = if (connected)
                                    MaterialTheme.colorScheme.onSurface.copy(alpha = 0.35f)
                                else
                                    Color.White
                            )
                        }
                    }
                }

                Spacer(Modifier.height(8.dp))

                Text("Host:Port", style = MaterialTheme.typography.labelSmall)
                Spacer(Modifier.height(4.dp))

                // Voll qualifiziert wie bei dir vorher
                androidx.compose.material3.OutlinedTextField(
                    value = host.address,
                    onValueChange = { newValue ->
                        if (!connected) onAddressChanged(newValue)
                    },
                    enabled = !connected,
                    singleLine = true,
                    textStyle = LocalTextStyle.current.copy(fontSize = 15.sp, lineHeight = 18.sp),
                    modifier = Modifier
                        .fillMaxWidth()
                        .heightIn(min = 44.dp)
                )

                Spacer(Modifier.height(10.dp))

                Text("Admin Password (for Autoscan)", style = MaterialTheme.typography.labelSmall)
                Spacer(Modifier.height(4.dp))

                Row(
                    modifier = Modifier.fillMaxWidth(),
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    androidx.compose.material3.OutlinedTextField(
                        value = host.adminPassword,
                        onValueChange = { newValue ->
                            if (!connected) onAdminPasswordChanged(newValue)
                        },
                        enabled = !connected,
                        singleLine = true,
                        textStyle = LocalTextStyle.current.copy(fontSize = 15.sp, lineHeight = 18.sp),
                        visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
                        keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
                        trailingIcon = {
                            val image = if (passwordVisible)
                                Icons.Filled.Visibility
                            else
                                Icons.Filled.VisibilityOff

                            val description = if (passwordVisible) "Hide password" else "Show password"

                            IconButton(onClick = { passwordVisible = !passwordVisible }) {
                                Icon(imageVector = image, contentDescription = description)
                            }
                        },
                        modifier = Modifier
                            .weight(1f)
                            .heightIn(min = 44.dp)
                    )

                    Spacer(Modifier.width(10.dp))

                    val buttonColor = when {
                        !isActive -> Color(0xFFD32F2F)
                        textConnected && pluginsConnected -> Color(0xFF90BF00)
                        textConnected || pluginsConnected -> Color(0xFFFFD600)
                        else -> Color(0xFFFF9800)
                    }

                    Button(
                        onClick = {
                            focusManager.clearFocus()
                            onConnectQuick(host)
                        },
                        modifier = Modifier
                            .height(40.dp)
                            .widthIn(min = 100.dp),
                        shape = RoundedCornerShape(8.dp),
                        colors = ButtonDefaults.buttonColors(
                            containerColor = buttonColor,
                            contentColor = Color.White
                        )
                    ) {
                        Text(
                            text = if (isActive) "Disconnect" else "Connect",
                            fontWeight = FontWeight.Bold,
                            fontSize = MaterialTheme.typography.labelMedium.fontSize
                        )
                    }
                }
            }
        }
    }

    // ---- Custom SVG-Style Icons ----

    @Composable
    fun PlayIconWhite(modifier: Modifier = Modifier) {
        Canvas(modifier = modifier) {
            val sizeMin = size.minDimension
            val w = sizeMin
            val h = sizeMin

            val path = Path().apply {
                // Links oben
                moveTo(w * 0.25f, h * 0.2f)
                // Links unten
                lineTo(w * 0.25f, h * 0.8f)
                // Rechts Mitte
                lineTo(w * 0.8f, h * 0.5f)
                close()
            }

            drawPath(
                path = path,
                color = Color.White
            )
        }
    }

    @Composable
    fun StopIconWhite(modifier: Modifier = Modifier) {
        Canvas(modifier = modifier) {
            val sizeMin = size.minDimension
            val padding = sizeMin * 0.2f
            val topLeft = Offset(padding, padding)
            val rectSize = Size(sizeMin - 2 * padding, sizeMin - 2 * padding)

            drawRect(
                color = Color.White,
                topLeft = topLeft,
                size = rectSize
            )
        }
    }

    // ---- About & Exit Dialogs ----

    private fun getAppVersion(context: Context): String {
        return try {
            val pm = context.packageManager
            val pkg = context.packageName
            @Suppress("DEPRECATION")
            val pi = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                pm.getPackageInfo(pkg, PackageManager.PackageInfoFlags.of(0))
            } else {
                pm.getPackageInfo(pkg, 0)
            }
            pi.versionName ?: "dev"
        } catch (_: Exception) {
            "dev"
        }
    }

    @Composable
    fun AboutDialog(onDismiss: () -> Unit) {
        val context = LocalContext.current
        val currentVersion = remember { getAppVersion(context) }

        AlertDialog(
            onDismissRequest = onDismiss,
            title = {
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.SpaceBetween,
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    Text("About")
                    IconButton(onClick = onDismiss, modifier = Modifier.size(24.dp)) {
                        Icon(
                            imageVector = Icons.Default.Close,
                            contentDescription = "Close",
                            tint = Color.White
                        )
                    }
                }
            },
            text = {
                Column(
                    modifier = Modifier
                        .fillMaxWidth()
                        .verticalScroll(rememberScrollState()),
                    horizontalAlignment = Alignment.Start
                ) {
                    Text("FMDX Web Connector")
                    Text("Version $currentVersion", style = MaterialTheme.typography.labelSmall)

                    Spacer(modifier = Modifier.height(12.dp))
                    Text("A WebSocket connector for TEF Logger communication with FMDX Webserver")
                    Spacer(modifier = Modifier.height(12.dp))
                    Text("© 2025 Highpoint")
                    Spacer(modifier = Modifier.height(12.dp))

                    Text(
                        text = "https://github.com/Highpoint2000/FMDXConnector",
                        color = Color(0xFF64B5F6),
                        modifier = Modifier.clickable {
                            val intent = Intent(
                                Intent.ACTION_VIEW,
                                Uri.parse("https://github.com/Highpoint2000/FMDXConnector")
                            )
                            context.startActivity(intent)
                        }
                    )
                    Spacer(modifier = Modifier.height(6.dp))

                    Text("Contact:")
                    Text(
                        text = "highpoint2000@gmail.com",
                        color = Color(0xFF64B5F6),
                        modifier = Modifier.clickable {
                            val intent = Intent(Intent.ACTION_SEND).apply {
                                type = "message/rfc822"
                                putExtra(Intent.EXTRA_EMAIL, arrayOf("highpoint2000@gmail.com"))
                                putExtra(Intent.EXTRA_SUBJECT, "FMDX Connector Feedback")
                            }
                            context.startActivity(intent)
                        }
                    )
                    Text("Discord: Highpoint2000")
                    Spacer(modifier = Modifier.height(12.dp))

                    Text(
                        text = "www.fmdx.org",
                        color = Color(0xFF64B5F6),
                        modifier = Modifier.clickable {
                            context.startActivity(
                                Intent(Intent.ACTION_VIEW, Uri.parse("http://www.fmdx.org"))
                            )
                        }
                    )
                    Spacer(modifier = Modifier.height(12.dp))
                    Text("Feedback welcome!")
                }
            },
            confirmButton = {
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.Start,
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    Button(
                        onClick = {
                            val intent = Intent(
                                Intent.ACTION_VIEW,
                                Uri.parse("https://www.buymeacoffee.com/Highpoint")
                            )
                            context.startActivity(intent)
                        },
                        modifier = Modifier.height(40.dp),
                        colors = ButtonDefaults.buttonColors(
                            containerColor = Color(0xFFFFD700),
                            contentColor = Color.Black
                        )
                    ) {
                        Text("☕ Buy Me A Coffee", fontWeight = FontWeight.Bold)
                    }
                }
            }
        )
    }

    @Composable
    fun ExitDialog(
        onDismiss: () -> Unit,
        onExit: () -> Unit
    ) {
        AlertDialog(
            onDismissRequest = onDismiss,
            title = { Text("Exit Application") },
            text = { Text("Do you really want to exit the application?") },
            confirmButton = {
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.spacedBy(12.dp)
                ) {
                    Button(
                        onClick = onDismiss,
                        colors = ButtonDefaults.buttonColors(
                            containerColor = Color(0xFF64B5F6),
                            contentColor = Color.White
                        ),
                        shape = RoundedCornerShape(8.dp),
                        modifier = Modifier.weight(1f)
                    ) { Text("Cancel") }

                    Button(
                        onClick = onExit,
                        colors = ButtonDefaults.buttonColors(
                            containerColor = Color(0xFF64B5F6),
                            contentColor = Color.White
                        ),
                        shape = RoundedCornerShape(8.dp),
                        modifier = Modifier.weight(1f)
                    ) { Text("Exit") }
                }
            }
        )
    }
}
