package com.epfl.esl.sportstracker

import android.annotation.SuppressLint
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
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.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.lifecycle.viewmodel.compose.viewModel
import co.yml.charts.axis.AxisData
import co.yml.charts.ui.linechart.LineChart
import co.yml.charts.ui.linechart.model.GridLines
import co.yml.charts.ui.linechart.model.IntersectionPoint
import co.yml.charts.ui.linechart.model.Line
import co.yml.charts.ui.linechart.model.LineChartData
import co.yml.charts.ui.linechart.model.LinePlotData
import co.yml.charts.ui.linechart.model.LineStyle
import co.yml.charts.ui.linechart.model.SelectionHighlightPoint
import co.yml.charts.ui.linechart.model.SelectionHighlightPopUp
import co.yml.charts.ui.linechart.model.ShadowUnderLine
import com.epfl.esl.sportstracker.ui.theme.SportsTrackerTheme
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.rememberPermissionState
import com.google.android.gms.maps.model.CameraPosition
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.wearable.DataClient
import com.google.android.gms.wearable.Wearable
import com.google.maps.android.compose.GoogleMap
import com.google.maps.android.compose.MapProperties
import com.google.maps.android.compose.MapType
import com.google.maps.android.compose.Marker
import com.google.maps.android.compose.rememberCameraPositionState
import com.google.maps.android.compose.rememberMarkerState

@SuppressLint("MissingPermission")
@OptIn(ExperimentalPermissionsApi::class)
@Composable
@androidx.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
fun ExerciseLiveScreen(
    device: DEVICE,
    dataClient: DataClient,
    modifier: Modifier = Modifier,
    exerciseLiveViewModel: ExerciseLiveViewModel = viewModel()
) {
    val context = LocalContext.current
    val heartRate by exerciseLiveViewModel.heartRate.observeAsState(initial = 0)
    val pointsData by exerciseLiveViewModel.heartRateList
        .observeAsState(initial = listOf())

    val locationData by exerciseLiveViewModel
        .locationData.observeAsState(initial = LocationData(
            46.5197,
            6.6323,
            "Lausanne"
        ))

    val cameraPermissionState = rememberPermissionState(
        android.Manifest.permission.ACCESS_FINE_LOCATION
    )

    LifecycleResumeEffect (0)  {
        if (device == DEVICE.SMARTWATCH) {
            dataClient.addListener(exerciseLiveViewModel)
            exerciseLiveViewModel.sendCommandToWear("Start", context)
        } else {
            exerciseLiveViewModel.scanLeDevice()
        }
        exerciseLiveViewModel.getLastLocation(context)

        onPauseOrDispose {
            if (device == DEVICE.SMARTWATCH) {
                dataClient.removeListener(exerciseLiveViewModel)
                exerciseLiveViewModel.sendCommandToWear("Stop", context)
            } else {
                exerciseLiveViewModel.stopBLE()
            }
        }
    }

    val cameraPositionState = rememberCameraPositionState()
    val markerState = rememberMarkerState()
    val currentPosition = LatLng(locationData.latitude, locationData.longitude)
    LaunchedEffect(key1 = currentPosition) {
        cameraPositionState.position =
            CameraPosition.fromLatLngZoom(currentPosition, 17f)
        markerState.position = currentPosition
    }

    Column(
        modifier = modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Column(
            modifier = modifier
                .weight(3f)
                .fillMaxSize(),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center
        ) {
            if (cameraPermissionState.hasPermission) {
                GoogleMap(
                    cameraPositionState = cameraPositionState,
                    properties = MapProperties(mapType = MapType.NORMAL)
                ){
                    Marker(
                        state = markerState,
                        title = stringResource(R.string.marker_title_text),
                        snippet = locationData.description
                    )
                }
            } else {
                Text(stringResource(R.string.location_permission_text))
                Button(onClick = { cameraPermissionState.launchPermissionRequest() }) {
                    Text(text = stringResource(R.string.location_permission_button_text))
                }
            }
        }

        Column(
            modifier = modifier
                .weight(1f)
        ) {
            Text(
                text = stringResource(R.string.heart_rate, heartRate),
                modifier = modifier
                    .padding(top = 8.dp, bottom = 8.dp)
            )
            Text(text = "Device ${device.value}")
        }

        val max = pointsData.maxOfOrNull { it.y }?.toInt() ?: 0
        val min = pointsData.minOfOrNull { it.y }?.toInt() ?: 0
        val steps = pointsData.size - 1

        Column(modifier = modifier.weight(3f)) {
            if (pointsData.isNotEmpty()) {
                val xAxisData = AxisData.Builder()
                    .axisStepSize(100.dp)
                    .backgroundColor(Color.Blue)
                    .steps(steps)
                    .axisStepSize(20.dp)
                    .labelData { i ->
                        i.toString()
                    }
                    .labelAndAxisLinePadding(15.dp)
                    .build()
                val yAxisData = AxisData.Builder()
                    .steps(max - min)
                    .backgroundColor(Color.Red)
                    .labelAndAxisLinePadding(20.dp)
                    .labelData { i ->
                        (i + min).toString()
                    }.build()
                val lineChartData = LineChartData(
                    linePlotData = LinePlotData(
                        lines = listOf(
                            Line(
                                dataPoints = pointsData,
                                LineStyle(),
                                IntersectionPoint(),
                                SelectionHighlightPoint(),
                                ShadowUnderLine(),
                                SelectionHighlightPopUp()
                            )
                        ),
                    ),
                    xAxisData = xAxisData,
                    yAxisData = yAxisData,
                    gridLines = GridLines(),
                    backgroundColor = Color.White
                )

                LineChart(
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(300.dp),
                    lineChartData = lineChartData
                )
            }
        }

    }
}



@Preview
@Composable
fun ExerciseLivePreview() {
    SportsTrackerTheme {
        val context = LocalContext.current
        val dataClient = Wearable.getDataClient(context)
        ExerciseLiveScreen(DEVICE.SMARTWATCH, dataClient)
    }
}
