package club.clubk.ktag.bletool

import android.Manifest
import android.annotation.SuppressLint
import android.bluetooth.BluetoothManager
import android.bluetooth.le.AdvertiseCallback
import android.bluetooth.le.AdvertiseData
import android.bluetooth.le.AdvertiseSettings
import android.content.Context
import android.content.pm.PackageManager
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.compose.foundation.BorderStroke
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
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.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.content.ContextCompat
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material.icons.Icons
import androidx.compose.material3.Icon
import android.content.Intent
import androidx.compose.material.icons.automirrored.filled.Send
import androidx.compose.material.icons.filled.Send
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.Scaffold

private const val TAG = "BLE Tool"

val advertisementPresets = listOf(
    AdvertisementPreset(
        "01 Instigate Game",
        byteArrayOf(
            0x01.toByte(), // Packet Type: Instigate Game
            0x00.toByte(), // Event Number
            0x00.toByte(),
            0x00.toByte(),
            0x00.toByte(),
            0x00.toByte(), // Game length (ms)
            0x88.toByte(),
            0x13.toByte(),
            0x00.toByte(),
            0x00.toByte(), // Time remaining until Countdown (ms)s
        ),
        "KTag Instigate Game Packet"
    ),
    AdvertisementPreset(
        "02 Event",
        byteArrayOf(
            0x02.toByte(), // Packet Type: Event Game
            0x00.toByte(), // Event Number
            0xFF.toByte(),
            0xFF.toByte(),
            0xFF.toByte(),
            0xFF.toByte(),
            0xFF.toByte(),
            0xFF.toByte(), // Target Bluetooth Device Address
            0x00.toByte(),
            0x00.toByte(),
            0x00.toByte(),
            0x00.toByte(), // Event ID
            0x00.toByte(),
            0x00.toByte(),
            0x00.toByte(),
            0x00.toByte(), // Event Data
        ),
        "KTag Event Packet"
    ),
    AdvertisementPreset(
        "03 Tag",
        byteArrayOf(
            0x03.toByte(), // Packet Type: Tag
            0x00.toByte(), // Event Number
            0x00.toByte(), // Tx Power level (dBm)
            0x00.toByte(), // Protocol
            0x00.toByte(), // Team ID
            0x00.toByte(), // Player ID
            0x0A.toByte(),
            0x00.toByte(), // Damage
            0x00.toByte(),
            0x00.toByte(),
            0x00.toByte(),
            0x00.toByte(), // Color
            0xFF.toByte(),
            0xFF.toByte(),
            0xFF.toByte(),
            0xFF.toByte(),
            0xFF.toByte(),
            0xFF.toByte(), // Target Bluetooth Device Address
        ),
        "KTag Tag Packet"
    ),
    AdvertisementPreset(
        "04 Console",
        byteArrayOf(
            0x04.toByte(), // Packet Type: Console
            0x00.toByte(), // Event Number
        ),
        "KTag Console Packet"
    ),
    AdvertisementPreset(
        "05 Status",
        byteArrayOf(
            0x05.toByte(), // Packet Type: Status
            0x00.toByte(), // Event Number
            0x00.toByte(), // Tx Power level (dBm)
            0x00.toByte(), // Protocol
            0x02.toByte(), // Team ID
            0x00.toByte(), // Player ID
            0x64.toByte(), 0x00.toByte(), // Health
            0x64.toByte(), 0x00.toByte(), // Maximum Health
            0xFE.toByte(), 0x00.toByte(), 0x00.toByte(), 0xFF.toByte(), // Primary Color
            0xFE.toByte(), 0xFF.toByte(), 0x00.toByte(), 0x00.toByte(), // Secondary Color
            0x07.toByte(), // SystemK Top-Level State
        ),
        "KTag Status Packet"
    ),
    AdvertisementPreset(
        "06 Parameters",
        byteArrayOf(
            0x06.toByte(), // Packet Type: Parameters
            0x00.toByte(), // Event Number
            0xFF.toByte(),
            0xFF.toByte(),
            0xFF.toByte(),
            0xFF.toByte(),
            0xFF.toByte(),
            0xFF.toByte(), // Target Bluetooth Device Address
            0x02.toByte(), // Subtype: Request Parameter Change
            0x01.toByte(),
            0x00.toByte(), // Key 1: Team ID
            0x02.toByte(),
            0x00.toByte(),
            0x00.toByte(),
            0x00.toByte(), // Value 1: 2
            0xFF.toByte(),
            0xFF.toByte(), // Key 2: Unused
            0x00.toByte(),
            0x00.toByte(),
            0x00.toByte(),
            0x00.toByte(), // Value 2: Unused
        ),
        "KTag Parameters Packet"
    ),
    AdvertisementPreset(
        "07 Hello",
        byteArrayOf(
            0x07.toByte(),  // Packet Type: Hello
            0x00.toByte(),  // Event Number
            0x01.toByte(),  // SystemK Major Version
            0x00.toByte(),  // SystemK Minor Version
            0x02.toByte(),  //
            0x00.toByte(),  // Device Type: Mobile App
            0x02.toByte(),  // Team ID
            0x4B.toByte(),  // 'K'
            0x54.toByte(),  // 'T'
            0x61.toByte(),  // 'a'
            0x67.toByte(),  // 'g'
            0x20.toByte(),  // ' '
            0x42.toByte(),  // 'B'
            0x4C.toByte(),  // 'L'
            0x45.toByte(),  // 'E'
            0x20.toByte(),  // ' '
            0x54.toByte(),  // 'T'
            0x6F.toByte(),  // 'o'
            0x6F.toByte(),  // 'o'
            0x6C.toByte(),  // 'l'
            0x00.toByte(),  // Device Name: "KTag BLE Tool"
        ),
        "KTag Hello Packet"
    ),
    AdvertisementPreset(
        "Empty",
        ByteArray(23) { 0 },
        "All zeros (clear current data)"
    )
)

@Composable
fun MainScreen() {
    var selectedTab by remember { mutableStateOf(0) }
    val context = LocalContext.current

    Scaffold(
        bottomBar = {
            NavigationBar {
                NavigationBarItem(
                    icon = { Icon(Icons.AutoMirrored.Filled.Send, "Advertiser") },
                    label = { Text("Advertise") },
                    selected = selectedTab == 0,
                    onClick = { selectedTab = 0 }
                )
                NavigationBarItem(
                    icon = { Icon(Icons.Default.Search, "Scanner") },
                    label = { Text("Scan") },
                    selected = selectedTab == 1,
                    onClick = {
                        context.startActivity(Intent(context, ScannerActivity::class.java))
                    }
                )
            }
        }
    ) { paddingValues ->
        Box(modifier = Modifier.padding(paddingValues)) {
            BleAdvertiserScreen()
        }
    }
}

class MainActivity : ComponentActivity() {
    private val requiredPermissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        arrayOf(
            Manifest.permission.BLUETOOTH_ADVERTISE,
            Manifest.permission.BLUETOOTH_CONNECT,
            Manifest.permission.BLUETOOTH_SCAN,
            Manifest.permission.ACCESS_FINE_LOCATION,  // Required for BLE operations
            Manifest.permission.ACCESS_COARSE_LOCATION  // Required for BLE operations
        )
    } else {
        arrayOf(
            Manifest.permission.BLUETOOTH,
            Manifest.permission.BLUETOOTH_ADMIN,
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION
        )
    }

    private val permissionLauncher = registerForActivityResult(
        ActivityResultContracts.RequestMultiplePermissions()
    ) { permissions ->
        val allGranted = permissions.entries.all { it.value }
        Log.d(TAG, "Permission results: ${permissions.map { "${it.key}: ${it.value}" }}")

        if (allGranted) {
            Log.i(TAG, "All permissions granted")
            setContent {
                MaterialTheme {
                    Surface(
                        modifier = Modifier.fillMaxSize(),
                        color = MaterialTheme.colorScheme.background
                    ) {
                        MainScreen()
                    }
                }
            }
        } else {
            // Show which permissions were denied
            val deniedPermissions = permissions.filter { !it.value }.keys
            Log.w(TAG, "Some permissions denied: $deniedPermissions")
            setContent {
                MaterialTheme {
                    Surface(
                        modifier = Modifier.fillMaxSize(),
                        color = MaterialTheme.colorScheme.background
                    ) {
                        PermissionDeniedScreen(
                            deniedPermissions = deniedPermissions.toList()
                        ) { requestPermissions() }
                    }
                }
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d(TAG, "onCreate called")
        checkAndRequestPermissions()
    }

    private fun checkAndRequestPermissions() {
        Log.d(TAG, "Checking permissions: ${requiredPermissions.joinToString()}")
        if (hasRequiredPermissions()) {
            Log.i(TAG, "All required permissions already granted")
            setContent {
                MaterialTheme {
                    Surface(
                        modifier = Modifier.fillMaxSize(),
                        color = MaterialTheme.colorScheme.background
                    ) {
                        MainScreen()
                    }
                }
            }
        } else {
            Log.i(TAG, "Requesting permissions")
            requestPermissions()
        }
    }

    private fun hasRequiredPermissions(): Boolean {
        return requiredPermissions.all { permission ->
            ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
        }
    }

    private fun requestPermissions() {
        Log.d(TAG, "Launching permission request")
        permissionLauncher.launch(requiredPermissions)
    }
}

@Composable
fun PermissionDeniedScreen(
    deniedPermissions: List<String>,
    onRequestPermissions: () -> Unit
) {
    Log.d(TAG, "Showing permission denied screen for permissions: $deniedPermissions")
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text(
            text = "The following permissions are required:",
            style = MaterialTheme.typography.bodyLarge,
            textAlign = TextAlign.Center,
            modifier = Modifier.padding(bottom = 8.dp)
        )
        deniedPermissions.forEach { permission ->
            Text(
                text = "• ${permission.split(".").last()}",
                style = MaterialTheme.typography.bodyMedium,
                textAlign = TextAlign.Center,
                modifier = Modifier.padding(vertical = 4.dp)
            )
        }
        Button(
            onClick = {
                Log.d(TAG, "Permission request button clicked")
                onRequestPermissions()
            },
            modifier = Modifier.padding(top = 16.dp)
        ) {
            Text("Grant Permissions")
        }
    }
}

private const val N_HEADER_BYTES = 8

@Composable
fun TitleBox() {
    Box(
        modifier = Modifier
            .padding(16.dp)
            .border(2.dp, MaterialTheme.colorScheme.primary)
            .padding(16.dp)
            .fillMaxWidth(),
        contentAlignment = Alignment.Center

    ) {
        Column {
            Text(
                text = "KTag BLE Tool",
                style = MaterialTheme.typography.headlineLarge.copy(
                    fontWeight = FontWeight.Bold,
                    color = MaterialTheme.colorScheme.primary
                )
            )
            Spacer(modifier = Modifier.height(8.dp))
            Text(
                text = "based on the specification 0.11",
                style = MaterialTheme.typography.labelSmall.copy(fontSize = 16.sp)
            )
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BleAdvertiserScreen() {
    Log.d(TAG, "Initializing BLE Advertiser screen")
    val context = LocalContext.current
    // Now store all 31 bytes (8 header + 23 data)
    var advertisementData by remember {
        mutableStateOf(ByteArray(31) { 0 }.apply {
            // Initialize header bytes
            this[0] = 0x1E.toByte()  // Length (30 bytes of data follow)
            this[1] = 0xFF.toByte()  // Type (Manufacturer Specific Data)
            this[2] = 0xFF.toByte()  // Manufacturer ID (Other) - First byte
            this[3] = 0xFF.toByte()  // Manufacturer ID (Other) - Second byte
            this[4] = 0x4B.toByte()  // KTag Packet Indicator - 'K'
            this[5] = 0x54.toByte()  // KTag Packet Indicator - 'T'
            this[6] = 0x61.toByte()  // KTag Packet Indicator - 'a'
            this[7] = 0x67.toByte()  // KTag Packet Indicator - 'g'
        })
    }
    var isAdvertising by remember { mutableStateOf(false) }
    var selectedByteIndex by remember { mutableIntStateOf(-1) }
    var errorMessage by remember { mutableStateOf<String?>(null) }
    var expandedDropdown by remember { mutableStateOf(false) }
    var selectedPreset by remember { mutableStateOf<AdvertisementPreset?>(null) }

    Column(
        modifier = Modifier.padding(16.dp)
    ) {
        TitleBox()

        // Create list of byte cells with their properties
        val byteCells = remember(advertisementData) {
            val packetType = advertisementData[8]
            advertisementData.mapIndexed { index, byte ->
                ByteCellData(
                    value = byte,
                    isHeader = index < N_HEADER_BYTES,
                    description = PacketFieldUtils.getFieldDescription(packetType, index),
                    backgroundColor = PacketFieldUtils.getFieldColor(packetType, index)
                )
            }
        }

        Column(
            modifier = Modifier.fillMaxSize(),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            // Error message display (unchanged)
            errorMessage?.let { message ->
                Log.e(TAG, "Showing error message: $message")
                Card(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(bottom = 16.dp),
                    colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.errorContainer)
                ) {
                    Text(
                        text = message,
                        modifier = Modifier.padding(16.dp),
                        color = MaterialTheme.colorScheme.onErrorContainer
                    )
                }
            }

            // Byte grid
            LazyVerticalGrid(
                columns = GridCells.Fixed(8),
                modifier = Modifier.weight(1f),
                contentPadding = PaddingValues(8.dp)
            ) {
                items(byteCells.size) { index ->
                    ByteCell(
                        data = byteCells[index],
                        isSelected = selectedByteIndex == index,
                        onClick = {
                            if (!byteCells[index].isHeader) {
                                Log.d(TAG, "Selected byte at index $index")
                                selectedByteIndex = index
                            }
                        }
                    )
                }
            }

            // Preset selector
            ExposedDropdownMenuBox(
                expanded = expandedDropdown,
                onExpandedChange = { expandedDropdown = it },
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(vertical = 8.dp)
            ) {
                OutlinedTextField(
                    value = selectedPreset?.name ?: "Select Preset",
                    onValueChange = {},
                    readOnly = true,
                    trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expandedDropdown) },
                    modifier = Modifier
                        .menuAnchor()
                        .fillMaxWidth()
                )
                ExposedDropdownMenu(
                    expanded = expandedDropdown,
                    onDismissRequest = { expandedDropdown = false }
                ) {
                    advertisementPresets.forEach { preset ->
                        DropdownMenuItem(
                            text = {
                                Column {
                                    Text(preset.name)
                                    Text(
                                        preset.description,
                                        style = MaterialTheme.typography.bodySmall,
                                        color = MaterialTheme.colorScheme.onSurfaceVariant
                                    )
                                }
                            },
                            onClick = {
                                Log.d(TAG, "Selected preset: ${preset.name}")
                                selectedPreset = preset
                                // Copy preset data after the header
                                advertisementData = advertisementData.copyOf().also {
                                    preset.data.copyInto(it, destinationOffset = 8)
                                }
                                expandedDropdown = false
                                selectedByteIndex = -1
                            }
                        )
                    }
                }
            }

            // Byte editor (only for non-header bytes)
            if (selectedByteIndex >= N_HEADER_BYTES) {
                ByteEditor(
                    currentValue = advertisementData[selectedByteIndex],
                    onValueChange = { newValue ->
                        Log.d(
                            TAG,
                            "Updating byte at index $selectedByteIndex to ${
                                String.format(
                                    "%02X",
                                    newValue
                                )
                            }"
                        )
                        advertisementData = advertisementData.copyOf().also {
                            it[selectedByteIndex] = newValue
                        }
                    }
                )
            }

            // Advertisement control button
            Button(
                onClick = {
                    try {
                        if (isAdvertising) {
                            Log.i(TAG, "Stopping advertisement")
                            stopAdvertising(context)
                        } else {
                            // Skip the first four bytes (length, type, mfg ID, mfg ID)  bytes when sending, because they get
                            // reconstructed later.
                            val payloadData =
                                advertisementData.copyOfRange(4, advertisementData.size)
                            Log.i(
                                TAG,
                                "Starting advertisement with data: ${
                                    advertisementData.joinToString {
                                        String.format(
                                            "%02X",
                                            it
                                        )
                                    }
                                }"
                            )
                            startAdvertising(context, payloadData)
                        }
                        isAdvertising = !isAdvertising
                        errorMessage = null
                    } catch (e: Exception) {
                        Log.e(TAG, "Error during advertisement operation", e)
                        errorMessage = "Error: ${e.message}"
                    }
                },
                modifier = Modifier
                    .padding(16.dp)
                    .fillMaxWidth()
            ) {
                Text(if (isAdvertising) "Stop Broadcasting" else "Start Broadcasting")
            }
        }
    }
}

@Composable
fun ByteCell(
    data: ByteCellData,
    isSelected: Boolean,
    onClick: () -> Unit
) {
    val backgroundColor = when {
        data.isHeader -> MaterialTheme.colorScheme.secondaryContainer
        isSelected -> MaterialTheme.colorScheme.primary
        data.backgroundColor != null -> data.backgroundColor
        else -> MaterialTheme.colorScheme.primaryContainer
    }

    Column {
        Card(
            modifier = Modifier
                .padding(N_HEADER_BYTES.dp)
                .size(48.dp),
            border = if (isSelected && !data.isHeader)
                BorderStroke(2.dp, MaterialTheme.colorScheme.primary)
            else null,
            colors = CardDefaults.cardColors(containerColor = backgroundColor),
            onClick = onClick
        ) {
            Box(
                modifier = Modifier.fillMaxSize(),
                contentAlignment = Alignment.Center
            ) {
                Text(
                    text = String.format("%02X", data.value),
                    style = MaterialTheme.typography.bodyMedium
                )
            }
        }
        if (data.description != "") {
            Text(
                text = data.description,
                style = MaterialTheme.typography.labelSmall,
                modifier = Modifier.padding(horizontal = N_HEADER_BYTES.dp),
                textAlign = TextAlign.Center
            )
        }
    }
}

@Composable
fun ByteEditor(
    currentValue: Byte,
    onValueChange: (Byte) -> Unit
) {
    var textValue by remember(currentValue) {
        mutableStateOf(String.format("%02X", currentValue))
    }

    OutlinedTextField(
        value = textValue,
        onValueChange = { newValue ->
            if (newValue.length <= 2 && newValue.all { it.isDigit() || it in 'A'..'F' || it in 'a'..'f' }) {
                textValue = newValue.uppercase()
                if (newValue.length == 2) {
                    onValueChange(newValue.toInt(16).toByte())
                }
            }
        },
        modifier = Modifier
            .padding(16.dp)
            .width(96.dp),
        label = { Text("Byte Value (Hex)") },
        singleLine = true
    )
}

@SuppressLint("MissingPermission")
private fun startAdvertising(context: Context, data: ByteArray) {
    Log.d(TAG, "Attempting to start advertising")
    val bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
    val bluetoothAdapter = bluetoothManager.adapter ?: run {
        Log.e(TAG, "Bluetooth not supported on this device")
        throw IllegalStateException("Bluetooth not supported")
    }

    if (!bluetoothAdapter.isEnabled) {
        Log.e(TAG, "Bluetooth is not enabled")
        throw IllegalStateException("Bluetooth is not enabled")
    }

    val advertiser = bluetoothAdapter.bluetoothLeAdvertiser ?: run {
        Log.e(TAG, "BLE advertising not supported on this device")
        throw IllegalStateException("BLE advertising not supported")
    }

    val settings = AdvertiseSettings.Builder()
        .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
        .setConnectable(false)
        .setTimeout(0)
        .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
        .build()

    // Calculate available space for manufacturer data
    // 2 bytes for manufacturer ID
    // Maximum total payload is 31 bytes
    // Format: [Length (1 byte)] [Type (1 byte)] [Manufacturer ID (2 bytes)] [Data (remaining bytes)]
    val maxManufacturerDataSize = 27  // 31 - 4 bytes overhead

    val truncatedData = if (data.size > maxManufacturerDataSize) {
        Log.w(
            TAG,
            "Data exceeded maximum size (${data.size} > $maxManufacturerDataSize bytes), truncating"
        )
        data.copyOfRange(0, maxManufacturerDataSize)
    } else {
        data
    }

    Log.d(TAG, "Advertisement structure:")
    Log.d(TAG, "- Total payload max: 31 bytes")
    Log.d(TAG, "- Overhead: 4 bytes (Length: 1, Type: 1, Manufacturer ID: 2)")
    Log.d(TAG, "- Available for manufacturer data: $maxManufacturerDataSize bytes")
    Log.d(TAG, "- Actual data size: ${truncatedData.size} bytes")
    Log.d(TAG, "- Data: ${truncatedData.joinToString(" ") { String.format("%02X", it) }}")

    val advertiseData = AdvertiseData.Builder()
        .addManufacturerData(0xFFFF, truncatedData)
        .build()

    Log.i(
        TAG, "Starting advertisement with settings: Mode=${settings.mode}, " +
                "TxPower=${settings.txPowerLevel}, Connectable=${settings.isConnectable}"
    )

    advertiser.startAdvertising(settings, advertiseData, advertisingCallback)
}

@SuppressLint("MissingPermission")
private fun stopAdvertising(context: Context) {
    Log.d(TAG, "Attempting to stop advertising")
    val bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
    val bluetoothAdapter = bluetoothManager.adapter
    val advertiser = bluetoothAdapter.bluetoothLeAdvertiser

    advertiser?.let {
        Log.i(TAG, "Stopping advertisement")
        it.stopAdvertising(advertisingCallback)
    } ?: Log.w(TAG, "Cannot stop advertising - advertiser is null")
}

private val advertisingCallback = object : AdvertiseCallback() {
    override fun onStartSuccess(settingsInEffect: AdvertiseSettings) {
        super.onStartSuccess(settingsInEffect)
        Log.i(
            TAG, "Advertisement started successfully with settings: " +
                    "Mode=${settingsInEffect.mode}, TxPower=${settingsInEffect.txPowerLevel}"
        )
    }

    override fun onStartFailure(errorCode: Int) {
        super.onStartFailure(errorCode)
        val errorMessage = when (errorCode) {
            ADVERTISE_FAILED_ALREADY_STARTED -> "Already started"
            ADVERTISE_FAILED_DATA_TOO_LARGE -> "Data too large"
            ADVERTISE_FAILED_TOO_MANY_ADVERTISERS -> "Too many advertisers"
            ADVERTISE_FAILED_INTERNAL_ERROR -> "Internal error"
            ADVERTISE_FAILED_FEATURE_UNSUPPORTED -> "Feature unsupported"
            else -> "Unknown error $errorCode"
        }
        Log.e(TAG, "Failed to start advertising: $errorMessage")
    }
}