package com.laseroptek.raman.ui.screens.info.base

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.laseroptek.raman.R
import com.laseroptek.raman.const.MAX_CHART_COLUMN_DATA_SIZE
import com.laseroptek.raman.data.model.chart.AnimationMode
import com.laseroptek.raman.data.model.chart.DividerProperties
import com.laseroptek.raman.data.model.chart.DotProperties
import com.laseroptek.raman.data.model.chart.GridProperties
import com.laseroptek.raman.data.model.chart.HorizontalIndicatorProperties
import com.laseroptek.raman.data.model.chart.LabelHelperProperties
import com.laseroptek.raman.data.model.chart.LabelProperties
import com.laseroptek.raman.data.model.chart.Line
import com.laseroptek.raman.data.model.chart.LineProperties
import com.laseroptek.raman.data.model.chart.PopupProperties
import com.laseroptek.raman.data.model.chart.StrokeStyle
import com.laseroptek.raman.data.model.serial.TemperatureTimeStamp
import com.laseroptek.raman.ui.screens.info.ChartUiState
import com.laseroptek.raman.utils.FixedSizeLIFOQueue
import com.laseroptek.raman.utils.ext.convertListToMutableStateList
import com.laseroptek.raman.utils.ext.convertListToMutableStateListBasedOnBoolean
import com.laseroptek.raman.utils.ext.format
import com.laseroptek.raman.utils.ext.px
import com.laseroptek.raman.utils.ext.toHHMMSSString
import com.laseroptek.raman.utils.ext.toYYYYMMDDHHMMSSString
import timber.log.Timber

val ubuntu @Composable
get() = FontFamily(
    Font(R.font.montserrat_regular, FontWeight.Normal),
    Font(R.font.montserrat_bold, FontWeight.Bold)
)

val gridProperties = GridProperties(
    xAxisProperties = GridProperties.AxisProperties(
        thickness = .2.dp,
        color = SolidColor(Color.Gray.copy(alpha = .5f)),
        style = StrokeStyle.Dashed(intervals = floatArrayOf(15f,15f), phase = 10f),
    ),
    yAxisProperties = GridProperties.AxisProperties(
        thickness = .2.dp,
        color = SolidColor(Color.Gray.copy(alpha = .5f)),
        style = StrokeStyle.Dashed(intervals = floatArrayOf(15f,15f), phase = 10f),
    ),
)
val dividerProperties = DividerProperties(
    xAxisProperties = LineProperties(
        thickness = .2.dp,
        color = SolidColor(Color.Gray.copy(alpha = .5f)),
        style = StrokeStyle.Dashed(intervals = floatArrayOf(15f,15f), phase = 10f),
    ),
    yAxisProperties = LineProperties(
        thickness = .2.dp,
        color = SolidColor(Color.Gray.copy(alpha = .5f)),
        style = StrokeStyle.Dashed(intervals = floatArrayOf(15f,15f), phase = 10f),
    )
)



@Composable
fun LineChartGraph(
    chartDataQueue: FixedSizeLIFOQueue<TemperatureTimeStamp> = FixedSizeLIFOQueue<TemperatureTimeStamp>(MAX_CHART_COLUMN_DATA_SIZE),
    isSystemMonitoring: Boolean = false,
    chartUiState: ChartUiState = ChartUiState(),
) {
    Timber.d("*** chartDataQueue (isSystemMonitoring: $isSystemMonitoring) ***")

    if (chartDataQueue.isEmpty()) {
        Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
            Text(
                text = "Waiting for data...",
                fontSize = 16.sp,
                color = Color.Gray
            )
        }
        return
    }

    val (processedData, timestampLabels) = remember(
chartDataQueue,
        isSystemMonitoring,
        chartUiState.intTempState,
        chartUiState.extTempState,
        chartUiState.intHumidityState,
        chartUiState.extHumidityState,
        chartUiState.ktpState,
        chartUiState.chamber1State,
        chartUiState.chamber2State,
        chartUiState.basePlateState,
        chartUiState.waterState
    ) {
        // 1. get last Max number of data points
        val finalData = chartDataQueue.toList().sortedBy{ it.timestamp }.takeLast(MAX_CHART_COLUMN_DATA_SIZE)

        // 2. Create the final data lists from the averaged data
        val intTempList = finalData.map { it.intTemperature.toDouble() }.convertListToMutableStateListBasedOnBoolean(chartUiState.intTempState)
        val extTempList = finalData.map { it.extTemperature.toDouble() }.convertListToMutableStateListBasedOnBoolean(chartUiState.extTempState)
        val intHumidityList = finalData.map { it.intHumidity.toDouble() }.convertListToMutableStateListBasedOnBoolean(chartUiState.intHumidityState)
        val extHumidityList = finalData.map { it.extHumidity.toDouble() }.convertListToMutableStateListBasedOnBoolean(chartUiState.extHumidityState)
        val ktpList = finalData.map { it.ktp.toDouble() }.convertListToMutableStateListBasedOnBoolean(chartUiState.ktpState)
        val chamber1List = finalData.map { it.chamber1.toDouble() }.convertListToMutableStateListBasedOnBoolean(chartUiState.chamber1State)
        val chamber2List = finalData.map { it.chamber2.toDouble() }.convertListToMutableStateListBasedOnBoolean(chartUiState.chamber2State)
        val basePlateList = finalData.map { it.basePlate.toDouble() }.convertListToMutableStateListBasedOnBoolean(chartUiState.basePlateState)
        val waterList = finalData.map { it.water.toDouble() }.convertListToMutableStateListBasedOnBoolean(chartUiState.waterState)

        // 3. CREATE THE TIMESTAMP LABELS from the averaged data
        val finalTimestamps = finalData.map { it.timestamp.toHHMMSSString() }
            .convertListToMutableStateList()

        // DEBUG
        Timber.d("*** finalTimestamps: ${finalTimestamps.takeLast(25).toList()} size: ${finalTimestamps.toList().size} ***")

        // DEBUG
        finalData.takeLast(25).forEachIndexed { idx, data ->
            val timestamp = data.timestamp
            val timestamps = data.timestamp.toYYYYMMDDHHMMSSString()
            Timber.d("[%02d] %s (%s)".format(idx, timestamps, timestamp.toString()))
        }

        // Prepare the Line data for the chart
        val data1 = listOf(
            Line(
                label = "Internal Temp",
                values = intTempList.toList(), // Pass a copy if Line expects an immutable list
                color = SolidColor(Color(255, 0, 0)),
                dotProperties = DotProperties(
                    strokeColor = SolidColor(Color(204, 0, 0)),
                )
            ),
            Line(
                label = "External Temp",
                values = extTempList.toList(),
                color = SolidColor(Color(255, 255, 0)),
                dotProperties = DotProperties(
                    strokeColor = SolidColor(Color(204, 204, 0)),
                )
            ),
            Line(
                label = "Internal Humidity",
                values = intHumidityList.toList(),
                color = SolidColor(Color(0, 255, 0)),
                dotProperties = DotProperties(
                    strokeColor = SolidColor(Color(0, 204, 0)),
                )
            ),
            Line(
                label = "External Humidity",
                values = extHumidityList.toList(),
                color = SolidColor(Color(0, 255, 255)),
                dotProperties = DotProperties(
                    strokeColor = SolidColor(Color(0, 204, 204)),
                )
            )
        )
        val data2 = listOf(
            // Use listOf for an immutable list, or mutableStateListOf if LineChart modifies it
            Line(
                label = "KTP",
                values = ktpList.toList(), // Pass a copy if Line expects an immutable list
                color = SolidColor(Color(255, 0, 0)),
                dotProperties = DotProperties(
                    strokeColor = SolidColor(Color(204, 0, 0)),
                )
            ),
            Line(
                label = "Chamber1",
                values = chamber1List.toList(),
                color = SolidColor(Color(255, 255, 0)),
                dotProperties = DotProperties(
                    strokeColor = SolidColor(Color(204, 204, 0)),
                )
            ),
            Line(
                label = "Chamber2",
                values = chamber2List.toList(),
                color = SolidColor(Color(0, 255, 0)),
                dotProperties = DotProperties(
                    strokeColor = SolidColor(Color(0, 204, 0)),
                )
            ),
            Line(
                label = "BasePlate",
                values = basePlateList.toList(),
                color = SolidColor(Color(0, 255, 255)),
                dotProperties = DotProperties(
                    strokeColor = SolidColor(Color(0, 204, 204)),
                )
            ),
            Line(
                label = "Water",
                values = waterList.toList(),
                color = SolidColor(Color(255, 0, 255)),
                dotProperties = DotProperties(
                    strokeColor = SolidColor(Color(204, 0, 204)),
                )
            ),
        )

        // Return the map of (processed data, labels) as a Pair
        (if (isSystemMonitoring) data2 else data1) to finalTimestamps
    }

    LineChart(
        modifier = Modifier
            .fillMaxSize()
            .padding(24.px.dp),
        data = processedData,
        animationMode = AnimationMode.Together(delayBuilder = {
            it * 500L
        }),
        gridProperties = gridProperties,
        dividerProperties = dividerProperties,
        popupProperties = PopupProperties(
            enabled = false,
            textStyle = TextStyle(
                fontSize = 8.sp,
                color = Color.Black,
                fontFamily = ubuntu
            ),
            contentBuilder = {
                it.format(1) // + " Million"
            },
            containerColor = Color.Transparent, //Color(0xff414141)
        ),
        indicatorProperties = HorizontalIndicatorProperties(
            enabled = true, // Enable labels on the y-axis (value / n)
            textStyle = TextStyle(
                fontSize = 8.sp,
                color = Color.Black,
                fontFamily = ubuntu
            ),
            contentBuilder = {
                it.format(1) // + " M"
            }
        ),
        labelHelperProperties = LabelHelperProperties(
            enabled = true,
            textStyle = TextStyle(fontSize = 8.sp, fontFamily = ubuntu, color = Color.Black)
        ),
        curvedEdges = false,
        labelProperties = LabelProperties(
            enabled = true, // Enable labels on the x-axis (time steamp)
            labels = timestampLabels.toList(),
            textStyle = TextStyle(
                fontSize = 8.sp,
                fontFamily = ubuntu, color = Color.Black
            ),
        ),
    )

}