package llc.arma.ble.app.ui.screen.ble

import android.os.SystemClock
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ContentAlpha
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf
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.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import llc.arma.ble.app.ui.common.SignalLevel
import llc.arma.ble.app.ui.common.rememberBottomDialogState
import llc.arma.ble.domain.model.BleInfo
import llc.arma.ble.domain.model.ConnectedBleInfo
import kotlin.math.pow

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BleListScreen(
    onNavigationEvent: (BleListContract.Effect.Navigation) -> Unit
) {

    val viewModel = hiltViewModel<BleListViewModel>()
    val state = viewModel.viewState.value

    val bottomDialog = rememberBottomDialogState()

    LaunchedEffect("effect"){
        viewModel.effect.onEach {
            when(it){
                is BleListContract.Effect.Navigation -> onNavigationEvent(it)
                is BleListContract.Effect.HideFilter -> launch {
                    bottomDialog.hide()
                }
                is BleListContract.Effect.ShowFilter -> launch {
                    bottomDialog.show {
                        Filter(
                            filter = viewModel.viewState.value.filter,
                            onEvent = {
                                viewModel.setEvent(it)
                            }
                        )
                    }
                }
            }
        }.launchIn(this)
    }

    Column {

        TopAppBar(
            title = {
                Text(text = "Arma BLE")
            },
            actions = {

                Row(
                    modifier = Modifier
                        .padding(horizontal = 8.dp)
                        .align(Alignment.CenterVertically)
                ) {

                    Text(text = "${state.bleList.size}")
                    
                    Spacer(modifier = Modifier.width(12.dp))
                    
                    Text(text = "${state.bleList.filter { 
                        it.batteryLevel == 100 
                    }.filterNot { SystemClock.elapsedRealtime() - it.scanTime > 10_000 }.size}")

                    Text(text = " | ")

                    Text(
                        text = "${state.bleList.filter { SystemClock.elapsedRealtime() - it.scanTime > 10_000 }.size}",
                        color = LocalContentColor.current.copy(alpha = ContentAlpha.disabled)
                    )

                    Text(text = " | ")

                    Text(
                        text = "${state.bleList.filter { it.batteryLevel < 100 }.size}",
                        color = MaterialTheme.colorScheme.error
                    )

                }

                IconButton(
                    onClick = {
                        viewModel.setEvent(BleListContract.Event.OnShowFilter)
                    }
                ) {

                    Icon(
                        imageVector = Icons.Rounded.FilterAlt,
                        contentDescription = null
                    )

                }

            }
        )

        val filteredData = state.bleList.filter {
            (it.type == state.filter.bleType || state.filter.bleType == null) &&
                    it.name.contains(state.filter.name) &&
                    it.serial.contains(state.filter.mac) &&
                    state.filter.rssi.contains(it.rssi?.toFloat() ?: Float.MIN_VALUE) &&
                    state.filter.battery.contains(it.batteryLevel.toFloat())
        }.let {
            when(state.filter.sortField){
                BleListContract.State.Filter.Field.Name -> it.sortedBy { it.name }
                BleListContract.State.Filter.Field.Mac -> it.sortedBy { it.serial }
                BleListContract.State.Filter.Field.Distance -> it.sortedBy { 10.0.pow((it.tx.toDouble() - (it.rssi?.toDouble() ?: 0.0) - 74) / 20).toFloat() }
                BleListContract.State.Filter.Field.Dbm -> it.sortedBy { it.rssi ?: 0 }
                BleListContract.State.Filter.Field.Battery -> it.sortedBy { it.batteryLevel  }
            }
        }.let {

            when(state.filter.sortOrder){
                BleListContract.State.Filter.Order.Asc -> it
                BleListContract.State.Filter.Order.Desc -> it.reversed()
            }

        }

        if(filteredData.isEmpty()){
            LinearProgressIndicator(
                strokeCap = StrokeCap.Round,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(3.dp)
            )
        }

        if(filteredData.isEmpty()){

            Box(modifier = Modifier.fillMaxSize()){
                Text(
                    modifier = Modifier.align(Alignment.Center),
                    style = MaterialTheme.typography.titleMedium,
                    text = "Метки в области не найдены"
                )
            }

        } else {
            LazyColumn(
                verticalArrangement = Arrangement.spacedBy(8.dp),
                modifier = Modifier.fillMaxSize()
            ) {

                items(items = state.connectedBleList){

                    ConnectedBleItem(ble = it) {
                        viewModel.setEvent(BleListContract.Event.OnConnectToBle(it.serial))
                    }

                }



                items(items = filteredData) {

                    BleItem(
                        ble = it,
                        onClick = {
                            viewModel.setEvent(BleListContract.Event.OnConnectToBle(it.serial))
                        }
                    )

                }

            }
        }

    }

}

@Composable
private fun ItemIcon(
    image: @Composable BoxScope.() -> Unit
){

    Surface(
        modifier = Modifier.size(40.dp),
        color = MaterialTheme.colorScheme.surfaceVariant,
        shape = CircleShape
    ) {
        Box(modifier = Modifier.fillMaxSize()) {

            image()

        }
    }

}

private fun Int.toSignalLevel(): Int {
    return when(this){
        in -30 downTo -52 -> 4
        in -51 downTo -63 -> 3
        in -62 downTo -75 -> 2
        in -74 downTo -89 -> 1
        else -> 0
    }
}

@Composable
private fun BleItem(
    ble: BleInfo,
    onClick: () -> Unit
){

    val color = if(ble.batteryLevel < 100){
        MaterialTheme.colorScheme.errorContainer
    } else {
        MaterialTheme.colorScheme.background
    }

    val highAlpha = ContentAlpha.high
    val disabledAlpha = ContentAlpha.disabled


    var time by remember {
        mutableLongStateOf(
            SystemClock.elapsedRealtime()
        )
    }

    LaunchedEffect(ble.scanTime) {
        while(true) {
            time = SystemClock.elapsedRealtime()
            delay(100)
        }
    }

    var alpha = if(SystemClock.elapsedRealtime() - ble.scanTime > 10_000){
        disabledAlpha
    } else {
        highAlpha
    }


    Row(
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.spacedBy(12.dp),
        modifier = Modifier
            .fillMaxWidth()
            .clip(RoundedCornerShape(16.dp))
            .background(color)
            .clickable { onClick() }
            .padding(vertical = 8.dp, horizontal = 16.dp)
            .alpha(alpha)

    ) {

        Box {

            ItemIcon {
                Icon(
                    modifier = Modifier.align(Alignment.Center),
                    imageVector = when (ble.type) {
                        BleInfo.Type.BEACON -> Icons.Rounded.Nfc
                        BleInfo.Type.THERMOMETER -> Icons.Rounded.Thermostat
                        BleInfo.Type.ACCELEROMETER -> Icons.Rounded.Speed
                    },
                    contentDescription = null
                )
            }

            if(ble.recordEnabled){

                Surface(
                    shape = CircleShape,
                    color = color,
                    modifier = Modifier.align(Alignment.TopEnd)
                ) {

                    Surface(
                        shape = CircleShape,
                        color = MaterialTheme.colorScheme.error,
                        modifier = Modifier.size(12.dp).padding(2.dp)
                    ) {

                    }

                }

            }

        }

        Column {

            Text(text = ble.name)

            Text(
                style = MaterialTheme.typography.bodyMedium,
                text = ble.serial
            )

            Row(
                verticalAlignment = Alignment.CenterVertically,
                modifier = Modifier.alpha(0.7f)
            ) {

                Icon(
                    modifier = Modifier.size(16.dp),
                    imageVector = Icons.Rounded.CompareArrows,
                    contentDescription = null
                )

                Spacer(modifier = Modifier.width(4.dp))

                Text(
                    style = MaterialTheme.typography.bodyMedium,
                    text = String.format("%.3f", (10.0.pow((ble.tx.toDouble() - (ble.rssi?.toDouble() ?: 0.0) - 74) / 20))) + " м."
                )

            }

            Row(
                horizontalArrangement = Arrangement.spacedBy(8.dp)
            ) {

                Row(
                    verticalAlignment = Alignment.CenterVertically,
                    modifier = Modifier.alpha(0.7f)
                ) {

                    SignalLevel(level = ble.rssi?.toSignalLevel() ?: 0)

                    Spacer(modifier = Modifier.width(4.dp))
                    
                    Box {

                        Text(
                            style = MaterialTheme.typography.bodyMedium,
                            text = "-999 dBm",
                            modifier = Modifier.alpha(0f)
                        )

                        Text(
                            style = MaterialTheme.typography.bodyMedium,
                            text = ble.rssi.toString() + " dBm"
                        )

                    }

                }

                Row(
                    verticalAlignment = Alignment.CenterVertically,
                    modifier = Modifier.alpha(0.7f)
                ) {

                    val color = if(ble.batteryLevel < 100){
                        MaterialTheme.colorScheme.error
                    } else {
                        LocalContentColor.current
                    }

                    Icon(
                        modifier = Modifier.size(16.dp),
                        imageVector = Icons.Rounded.BatteryFull,
                        contentDescription = null,
                        tint = color
                    )

                    Box {

                        Text(
                            style = MaterialTheme.typography.bodyMedium,
                            text = "100 %",
                            modifier = Modifier.alpha(0f)
                        )

                        Text(
                            style = MaterialTheme.typography.bodyMedium,
                            text = ble.batteryLevel.toString() + " %",
                            color = color
                        )

                    }


                }

                Row(
                    verticalAlignment = Alignment.CenterVertically,
                    modifier = Modifier.alpha(0.7f)
                ) {

                    Icon(
                        modifier = Modifier.size(16.dp),
                        imageVector = Icons.Rounded.ArrowRightAlt,
                        contentDescription = null
                    )

                    Box {

                        Text(
                            style = MaterialTheme.typography.bodyMedium,
                            text = "99s",
                            modifier = Modifier.alpha(0f)
                        )

                        Text(
                            style = MaterialTheme.typography.bodyMedium,
                            text = ">1m",
                            modifier = Modifier.alpha(0f)
                        )

                        val lastAdv = ((time - ble.scanTime) / 1_000)

                        Text(
                            style = MaterialTheme.typography.bodyMedium,
                            text = if(lastAdv > 60){
                                ">1m"
                            } else {
                                "${lastAdv}s"
                            }
                        )

                    }


                }


            }

        }

    }

}

@Composable
private fun ConnectedBleItem(
    ble: ConnectedBleInfo,
    onClick: () -> Unit
){

    Row(
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.spacedBy(12.dp),
        modifier = Modifier
            .fillMaxWidth()
            .clip(RoundedCornerShape(16.dp))
            .clickable { onClick() }
            .background(MaterialTheme.colorScheme.tertiaryContainer.copy(alpha = .99f))
            .padding(vertical = 8.dp, horizontal = 16.dp)

    ) {

        ItemIcon {
            Icon(
                modifier = Modifier.align(Alignment.Center),
                imageVector = Icons.Rounded.Link,
                contentDescription = null
            )
        }

        Column {

            Text(text = ble.name)

            Text(
                style = MaterialTheme.typography.bodyMedium,
                text = ble.serial
            )

            Row(
                horizontalArrangement = Arrangement.spacedBy(8.dp)
            ) {

                Row(
                    verticalAlignment = Alignment.CenterVertically,
                    modifier = Modifier.alpha(0.7f)
                ) {

                    Text(
                        style = MaterialTheme.typography.bodyMedium,
                        text = "Соединено"
                    )

                }
            }

        }

    }

}