package de.mm20.launcher2.ui.launcher.widgets.weather

import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.res.Resources
import android.net.Uri
import android.text.format.DateUtils
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.SharedTransitionScope
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.expandHorizontally
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkHorizontally
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
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.rotate
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalResources
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.app.ActivityOptionsCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.repeatOnLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.ktx.tryStartActivity
import de.mm20.launcher2.preferences.MeasurementSystem
import de.mm20.launcher2.preferences.TimeFormat
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.common.WeatherLocationSearchDialog
import de.mm20.launcher2.ui.component.Banner
import de.mm20.launcher2.ui.component.MissingPermissionBanner
import de.mm20.launcher2.ui.component.weather.AnimatedWeatherIcon
import de.mm20.launcher2.ui.component.weather.WeatherIcon
import de.mm20.launcher2.ui.component.weather.WeatherIconDefaults
import de.mm20.launcher2.ui.ktx.animateShapeAsState
import de.mm20.launcher2.ui.locals.LocalMeasurementSystem
import de.mm20.launcher2.ui.locals.LocalTimeFormat
import de.mm20.launcher2.ui.theme.transparency.transparency
import de.mm20.launcher2.ui.utils.formatPercent
import de.mm20.launcher2.ui.utils.formatPrecipitation
import de.mm20.launcher2.ui.utils.formatSpeed
import de.mm20.launcher2.ui.utils.formatTemperature
import de.mm20.launcher2.weather.DailyForecast
import de.mm20.launcher2.weather.Forecast
import de.mm20.launcher2.widgets.WeatherWidget
import java.text.SimpleDateFormat
import kotlin.math.roundToInt

@Composable
fun WeatherWidget(widget: WeatherWidget) {
    val viewModel: WeatherWidgetVM = viewModel(key = "weather-widget-${widget.id}")

    val context = LocalContext.current
    val lifecycleOwner = LocalLifecycleOwner.current

    LaunchedEffect(null) {
        lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
            viewModel.selectNow()
        }
    }

    val selectedForecast by viewModel.currentForecast

    val measurementSystem = LocalMeasurementSystem.current
    val timeFormat = LocalTimeFormat.current

    val compactMode = !widget.config.showForecast

    val isProviderAvailable by viewModel.isProviderAvailable.collectAsStateWithLifecycle(true)

    var showLocationDialog by remember { mutableStateOf(false) }

    WeatherLocationSearchDialog(
        expanded = showLocationDialog,
        onDismissRequest = { showLocationDialog = false }
    )


    Column {
        if (!isProviderAvailable) {
            Banner(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(16.dp),
                text = stringResource(R.string.weather_widget_no_provider),
                icon = R.drawable.error_24px,
                primaryAction = {
                    Button(
                        onClick = {
                            viewModel.openSettings(context)
                        },
                        contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
                    ) {
                        Icon(
                            painterResource(R.drawable.open_in_new_24px),
                            null,
                            modifier = Modifier
                                .padding(end = ButtonDefaults.IconSpacing)
                                .size(ButtonDefaults.IconSize)
                        )
                        Text(stringResource(R.string.settings))
                    }
                }
            )
        }

        val forecast = selectedForecast ?: run {
            val hasPermission by viewModel.hasLocationPermission.collectAsState()
            val autoLocation by viewModel.autoLocation.collectAsState()
            AnimatedVisibility(hasPermission == false && autoLocation == true) {
                MissingPermissionBanner(
                    modifier = Modifier
                        .padding(horizontal = 16.dp)
                        .padding(top = 16.dp),
                    text = stringResource(id = R.string.missing_permission_auto_location),
                    onClick = {
                        viewModel.requestLocationPermission(context as AppCompatActivity)
                    },
                    secondaryAction = {
                        OutlinedButton(onClick = {
                            showLocationDialog = true
                        }) {
                            Text(
                                stringResource(R.string.weather_widget_set_location),
                            )
                        }
                    }
                )
            }
            NoData()
            return
        }


        CurrentWeather(forecast, measurementSystem, timeFormat)

        if (!compactMode) {

            val dailyForecasts by viewModel.dailyForecasts
            val selectedDayForecast by viewModel.currentDailyForecast
            val currentDayForecasts by viewModel.currentDayForecasts

            Surface(
                color = MaterialTheme.colorScheme.surfaceContainer.copy(alpha = MaterialTheme.transparency.surface),
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(start = 8.dp, bottom = 8.dp, end = 8.dp),
                shape = MaterialTheme.shapes.small,
            ) {
                Column(
                    modifier = Modifier.padding(top = 8.dp, bottom = 8.dp)
                ) {
                    AnimatedContent(
                        currentDayForecasts to forecast,
                        contentKey = { it.first },
                        transitionSpec = {
                            fadeIn() togetherWith fadeOut()
                        }
                    ) { (fcs, fc) ->
                        WeatherTimeSelector(
                            forecasts = fcs,
                            selectedForecast = fc,
                            measurementSystem = measurementSystem,
                            timeFormat = timeFormat,
                            onTimeSelected = {
                                viewModel.selectForecast(it)
                            },
                            modifier = Modifier.padding(bottom = 8.dp)
                        )
                    }
                    selectedDayForecast?.let {
                        WeatherDaySelector(
                            days = dailyForecasts,
                            selectedDay = it,
                            onDaySelected = {
                                viewModel.selectDay(it)
                            },
                            measurementSystem = measurementSystem,
                        )
                    }
                }
            }
        }
    }
}

@Composable
fun CurrentWeather(
    forecast: Forecast,
    measurementSystem: MeasurementSystem,
    timeFormat: TimeFormat,
) {
    val context = LocalContext.current
    val weatherApp = remember {
        context.packageManager.resolveActivity(
            Intent(Intent.ACTION_MAIN).also {
                it.addCategory(Intent.CATEGORY_APP_WEATHER)
            }, 0
        )
    }


    var bounds by remember { mutableStateOf(Rect.Zero) }
    val view = LocalView.current
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .height(IntrinsicSize.Max)
            .onPlaced {
                val size = it.size
                val offset = it.localToRoot(Offset.Zero)
                bounds = Rect(
                    offset.x,
                    offset.y,
                    offset.x + size.width,
                    offset.y + size.height
                )
            }
            .clickable(
                enabled = weatherApp != null,
                onClick = {
                    context.tryStartActivity(
                        Intent().also {
                            it.component = weatherApp?.activityInfo?.let {
                                ComponentName(it.packageName, it.name)
                            }
                        },
                        ActivityOptionsCompat.makeClipRevealAnimation(
                            view,
                            bounds.left.toInt(),
                            bounds.top.toInt(),
                            bounds.width.toInt(),
                            bounds.height.toInt()
                        ).toBundle()
                    )
                },
                interactionSource = remember { MutableInteractionSource() },
                indication = LocalIndication.current,
            ),
        horizontalArrangement = Arrangement.spacedBy(16.dp),
    ) {

        Column(
            modifier = Modifier
                .weight(1f)
                .fillMaxHeight()
                .padding(
                    top = 16.dp,
                    end = 16.dp,
                    start = 16.dp,
                    bottom = 8.dp,
                )
        ) {
            Text(
                text = forecast.location,
                style = MaterialTheme.typography.titleMedium
            )

            Text(
                modifier = Modifier.padding(vertical = 2.dp),
                text = formatTemperature(
                    context,
                    forecast.temperature.toFloat(),
                    measurementSystem
                ),
                style = MaterialTheme.typography.headlineLarge,
            )

            Text(
                text = forecast.condition,
                style = MaterialTheme.typography.bodySmall,
                color = MaterialTheme.colorScheme.secondary,
            )

            Spacer(modifier = Modifier.weight(1f))

            Text(
                text = "${forecast.provider} (${
                    formatTime(
                        LocalContext.current,
                        forecast.updateTime,
                        timeFormat,
                    )
                })",
                style = MaterialTheme.typography.bodySmall.copy(fontSize = 8.sp),
                color = MaterialTheme.colorScheme.onSurfaceVariant,
                modifier = Modifier
                    .offset(-16.dp, 4.dp)
                    .clickable(onClick = {
                        val intent = Intent(Intent.ACTION_VIEW).apply {
                            data = Uri.parse(forecast.providerUrl)
                                ?: return@clickable
                        }
                        context.tryStartActivity(intent)
                    })
                    .padding(horizontal = 16.dp, vertical = 4.dp)
            )


        }

        Column(
            modifier = Modifier
                .weight(1f)
                .fillMaxHeight()
                .padding(
                    end = 16.dp,
                    top = 16.dp,
                    bottom = 16.dp,
                ),
            horizontalAlignment = Alignment.End,
        ) {

            AnimatedWeatherIcon(
                modifier = Modifier.offset(8.dp, -8.dp),
                icon = weatherIconById(forecast.icon),
                night = forecast.night,
                WeatherIconDefaults.colors(MaterialTheme.colorScheme.surface)
            )

            CurrentWeatherDetails(
                modifier = Modifier.weight(1f),
                forecast = forecast,
                measurementSystem = measurementSystem,
            )
        }
    }
}

@Composable
private fun CurrentWeatherDetails(
    modifier: Modifier = Modifier,
    forecast: Forecast,
    measurementSystem: MeasurementSystem
) {
    val context = LocalContext.current
    val resources = LocalResources.current

    val items = remember(forecast) {
        buildList<Triple<String, @Composable () -> Unit, String>> {
            if (
                forecast.precipProbability != null && forecast.precipProbability!! >= 20 ||
                forecast.precipitation != null && forecast.precipitation!! >= 1
            ) {
                add(
                    Triple(
                        "rain",
                        @Composable {
                            Icon(
                                painter = painterResource(R.drawable.rainy_20px),
                                modifier = Modifier
                                    .size(20.dp),
                                contentDescription = null,
                                tint = MaterialTheme.colorScheme.secondary,
                            )
                        },
                        when {
                            forecast.precipProbability != null
                                    && forecast.precipitation != null
                                    && forecast.precipitation!! >= 0.05 -> {
                                "${
                                    formatPercent(
                                        forecast.precipProbability!!.toFloat()
                                    )
                                } • ${
                                    formatPrecipitation(
                                        context,
                                        forecast.precipitation?.toFloat() ?: 0f,
                                        measurementSystem
                                    )
                                }"

                            }

                            forecast.precipProbability != null -> {
                                formatPercent(forecast.precipProbability!!.toFloat())
                            }

                            else -> {
                                formatPrecipitation(
                                    context,
                                    forecast.precipitation?.toFloat() ?: 0f,
                                    measurementSystem
                                )
                            }
                        }
                    )
                )
            }
            if (forecast.uvIndex != null && forecast.uvIndex!! >= 3) {
                add(
                    Triple(
                        "uv",
                        @Composable {
                            Icon(
                                painter = painterResource(R.drawable.sunny_20px),
                                modifier = Modifier
                                    .size(20.dp),
                                contentDescription = null,
                                tint = MaterialTheme.colorScheme.secondary,
                            )
                        },
                        resources.getString(R.string.uv_index, forecast.uvIndex?.roundToInt())
                    )

                )
            }
            if (forecast.windSpeed != null && forecast.windSpeed!! >= 3) {
                add(
                    Triple(
                        "wind",
                        @Composable {
                            if (forecast.windDirection != null) {
                                // windDirection is "fromDirection"; Wind (arrow) blows into opposite direction
                                val angle by animateFloatAsState(forecast.windDirection!!.toFloat() + 180f)
                                Icon(
                                    painter = painterResource(R.drawable.navigation_20px),
                                    modifier = Modifier
                                        .rotate(angle)
                                        .size(20.dp),
                                    contentDescription = null,
                                    tint = MaterialTheme.colorScheme.secondary,
                                )
                            } else {
                                Icon(
                                    painter = painterResource(R.drawable.air_20px),
                                    contentDescription = null,
                                    modifier = Modifier.size(20.dp),
                                    tint = MaterialTheme.colorScheme.secondary,
                                )
                            }
                        },
                        formatSpeed(
                            context,
                            forecast.windSpeed!!.toFloat(),
                            measurementSystem
                        )
                    )
                )
            }
            if (size < 4 && forecast.humidity != null && forecast.temperature >= 293.15) {
                add(
                    Triple(
                        "humidity",
                        @Composable {
                            Icon(
                                painter = painterResource(R.drawable.humidity_mid_20px),
                                modifier = Modifier
                                    .size(20.dp),
                                contentDescription = null,
                                tint = MaterialTheme.colorScheme.secondary,
                            )
                        },
                        formatPercent(forecast.humidity!!.toFloat())
                    ),
                )
            }
            if (size < 4 && forecast.clouds != null && forecast.clouds!! >= 10) {
                add(
                    Triple(
                        "clouds",
                        @Composable {
                            Icon(
                                painter = painterResource(R.drawable.cloud_20px),
                                modifier = Modifier
                                    .size(20.dp),
                                contentDescription = null,
                                tint = MaterialTheme.colorScheme.secondary,
                            )
                        },
                        formatPercent(forecast.clouds!!.toFloat())
                    ),
                )
            }
        }
    }


    SharedTransitionScope {
        AnimatedContent(
            items,
            modifier = it,
        ) { items ->
            FlowRow(
                modifier = modifier,
                verticalArrangement = Arrangement.spacedBy(8.dp),
                horizontalArrangement = Arrangement.spacedBy(16.dp, Alignment.End),
            ) {
                for (item in items) {
                    Row(
                        verticalAlignment = Alignment.CenterVertically,
                    ) {
                        Box(
                            modifier = Modifier.sharedElement(
                                rememberSharedContentState(
                                    key = item.first,
                                ),
                                placeholderSize = SharedTransitionScope.PlaceholderSize.AnimatedSize,
                                animatedVisibilityScope = this@AnimatedContent,
                            )
                        ) {
                            item.second()
                        }
                        Text(
                            textAlign = TextAlign.Start,
                            modifier = Modifier.padding(start = 4.dp).sharedBounds(
                                rememberSharedContentState(
                                    key = item.first + "text",
                                ),
                                placeholderSize = SharedTransitionScope.PlaceholderSize.AnimatedSize,
                                animatedVisibilityScope = this@AnimatedContent,
                            ),
                            text = item.third,
                            style = MaterialTheme.typography.labelSmall,
                        )
                    }
                }
            }
        }
    }
}

@Composable
fun WeatherTimeSelector(
    modifier: Modifier = Modifier,
    forecasts: List<Forecast>,
    selectedForecast: Forecast,
    measurementSystem: MeasurementSystem,
    timeFormat: TimeFormat,
    onTimeSelected: (Int) -> Unit
) {
    val context = LocalContext.current

    val listState = rememberLazyListState()

    val colors = WeatherIconDefaults.colors(MaterialTheme.colorScheme.surfaceBright)
    val selectedColors = WeatherIconDefaults.themedColors(
        MaterialTheme.colorScheme.secondary,
    )

    LazyRow(
        state = listState,
        modifier = modifier
            .fillMaxWidth(),
        horizontalArrangement = Arrangement.spacedBy(2.dp),
        contentPadding = PaddingValues(start = 8.dp, end = 8.dp),
        verticalAlignment = Alignment.CenterVertically
    ) {
        itemsIndexed(forecasts, key = { idx, _ -> idx }) { idx, fc ->
            val selected = fc == selectedForecast
            val sm = MaterialTheme.shapes.small
            val xs = MaterialTheme.shapes.extraSmall
            Surface(
                shape = animateShapeAsState(
                    when {
                        selected -> sm
                        idx == 0 -> xs.copy(
                            topStart = sm.topStart,
                            bottomStart = sm.bottomStart
                        )

                        idx == forecasts.lastIndex -> xs.copy(
                            topEnd = sm.topEnd,
                            bottomEnd = sm.bottomEnd
                        )

                        else -> MaterialTheme.shapes.extraSmall
                    }
                ).value,
                modifier = Modifier
                    .widthIn(min = 60.dp),
                color = if (selected) MaterialTheme.colorScheme.secondary else MaterialTheme.colorScheme.surfaceBright,
                contentColor = if (selected) MaterialTheme.colorScheme.onSecondary else MaterialTheme.colorScheme.onSurfaceVariant,
            ) {
                Column(
                    modifier = Modifier
                        .clickable { onTimeSelected(idx) }
                        .padding(start = 4.dp, end = 4.dp, top = 8.dp, bottom = 4.dp),
                    horizontalAlignment = Alignment.CenterHorizontally,
                ) {
                    WeatherIcon(
                        modifier = Modifier
                            .align(Alignment.CenterHorizontally)
                            .semantics {
                                contentDescription = fc.condition
                            }
                            .padding(bottom = 4.dp),
                        icon = weatherIconById(fc.icon),
                        night = fc.night,
                        colors = if (selected) selectedColors else colors
                    )
                    Text(
                        text = formatTime(context, fc.timestamp, timeFormat),
                        style = MaterialTheme.typography.labelSmall,
                        softWrap = false,
                        modifier = Modifier.align(Alignment.CenterHorizontally)
                    )
                    Box(
                        contentAlignment = Alignment.Center
                    ) {
                        val alpha by animateFloatAsState(if (selected) 0f else 1f)
                        Text(
                            modifier = Modifier
                                .alpha(alpha),
                            text = formatTemperature(
                                context,
                                fc.temperature.toFloat(),
                                measurementSystem
                            ),
                            softWrap = false,
                            style = MaterialTheme.typography.labelSmall,
                        )
                        Box(
                            modifier = Modifier
                                .alpha(1f - alpha)
                                .requiredSize(8.dp)
                                .background(
                                    MaterialTheme.colorScheme.onSecondary,
                                    CircleShape
                                )
                        )
                    }
                }
            }
        }
    }
}

@Composable
fun WeatherDaySelector(
    modifier: Modifier = Modifier,
    days: List<DailyForecast>,
    selectedDay: DailyForecast,
    onDaySelected: (Int) -> Unit,
    measurementSystem: MeasurementSystem
) {
    val dateFormat = SimpleDateFormat("EEE")
    val context = LocalContext.current

    val colors = WeatherIconDefaults.colors(MaterialTheme.colorScheme.surfaceBright)
    val selectedColors = WeatherIconDefaults.themedColors(
        MaterialTheme.colorScheme.secondary,
    )

    val listState = rememberLazyListState()
    LazyRow(
        state = listState,
        modifier = modifier
            .fillMaxWidth(),
        horizontalArrangement = Arrangement.spacedBy(2.dp),
        verticalAlignment = Alignment.CenterVertically,
        contentPadding = PaddingValues(start = 8.dp, end = 8.dp),
    ) {
        itemsIndexed(days, key = { idx, _ -> idx }) { idx, day ->
            val selected = day == selectedDay

            val sm = MaterialTheme.shapes.small
            val xs = MaterialTheme.shapes.extraSmall
            Surface(
                shape = animateShapeAsState(
                    when {
                        selected -> sm
                        idx == 0 -> xs.copy(
                            topStart = sm.topStart,
                            bottomStart = sm.bottomStart
                        )

                        idx == days.lastIndex -> xs.copy(
                            topEnd = sm.topEnd,
                            bottomEnd = sm.bottomEnd
                        )

                        else -> MaterialTheme.shapes.extraSmall
                    }
                ).value,
                color = if (selected) MaterialTheme.colorScheme.secondary else MaterialTheme.colorScheme.surfaceBright,
                contentColor = if (selected) MaterialTheme.colorScheme.onSecondary else MaterialTheme.colorScheme.onSurfaceVariant,
            ) {
                Row(
                    modifier = Modifier
                        .clickable { onDaySelected(idx) }
                        .padding(top = 4.dp, bottom = 4.dp, start = 4.dp, end = 8.dp),
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    WeatherIcon(
                        icon = weatherIconById(day.icon),
                        colors = if (selected) selectedColors else colors
                    )
                    Text(
                        modifier = Modifier.padding(start = 8.dp),
                        text = "${dateFormat.format(day.timestamp)} " +
                                "${
                                    formatTemperature(
                                        context,
                                        day.minTemp.toFloat(),
                                        measurementSystem
                                    )
                                } / " +
                                formatTemperature(
                                    context,
                                    day.maxTemp.toFloat(),
                                    measurementSystem
                                ),
                        softWrap = false,
                        style = MaterialTheme.typography.labelSmall,
                    )
                    val spec = MaterialTheme.motionScheme.fastSpatialSpec<IntSize>()
                    AnimatedVisibility(
                        selected,
                        enter = fadeIn() + expandHorizontally(spec),
                        exit = fadeOut() + shrinkHorizontally(spec),
                    ) {
                        Box(
                            modifier = Modifier
                                .padding(start = 8.dp)
                                .size(8.dp)
                                .background(
                                    MaterialTheme.colorScheme.onSecondary,
                                    CircleShape
                                )
                        )
                    }
                }
            }
        }
    }
}

private fun formatTime(context: Context, timestamp: Long, timeFormat: TimeFormat): String {
    val timeFormatFlag = when (timeFormat) {
        TimeFormat.TwelveHour -> DateUtils.FORMAT_12HOUR
        TimeFormat.TwentyFourHour -> DateUtils.FORMAT_24HOUR
        else -> 0
    }

    return DateUtils.formatDateTime(
        context,
        timestamp,
        DateUtils.FORMAT_SHOW_TIME or timeFormatFlag
    )
}

private fun windDirectionAsWord(resources: Resources, direction: Double): String {
    return resources.getString(
        when (direction) {
            in 11.25..33.75 -> R.string.wind_north_north_east
            in 33.75..56.25 -> R.string.wind_north_east
            in 56.25..78.75 -> R.string.wind_east_north_east
            in 78.75..101.25 -> R.string.wind_east
            in 101.25..123.75 -> R.string.wind_east_south_east
            in 123.75..146.25 -> R.string.wind_south_east
            in 146.25..168.75 -> R.string.wind_south_south_east
            in 168.75..191.25 -> R.string.wind_south
            in 191.25..213.75 -> R.string.wind_south_south_west
            in 213.75..236.25 -> R.string.wind_south_west
            in 236.25..258.75 -> R.string.wind_west_south_west
            in 258.75..281.25 -> R.string.wind_west
            in 281.25..303.75 -> R.string.wind_west_north_west
            in 303.75..326.25 -> R.string.wind_north_west
            in 326.25..348.75 -> R.string.wind_north_north_west
            else -> R.string.wind_north
        }
    )
}

private fun weatherIconById(id: Int): WeatherIcon {
    return when (id) {
        Forecast.CLEAR -> WeatherIcon.Clear
        Forecast.OVERCAST -> WeatherIcon.Overcast
        Forecast.EXTREME_COLD -> WeatherIcon.ExtremeHeat
        Forecast.LIGHT_RAIN -> WeatherIcon.LightRain
        Forecast.HAZE -> WeatherIcon.Haze
        Forecast.FOG -> WeatherIcon.Fog
        Forecast.HAIL -> WeatherIcon.Hail
        Forecast.EXTREME_HEAT -> WeatherIcon.ExtremeHeat
        Forecast.PARTLY_CLOUDY -> WeatherIcon.PartlyCloudy
        Forecast.RAIN -> WeatherIcon.Rain
        Forecast.HEAVY_RAIN -> WeatherIcon.HeavyRain
        Forecast.SLEET -> WeatherIcon.Sleet
        Forecast.SNOW -> WeatherIcon.Snow
        Forecast.THUNDER -> WeatherIcon.Thunder
        Forecast.THUNDERSTORM -> WeatherIcon.Thunderstorm
        Forecast.WIND -> WeatherIcon.Wind
        Forecast.MOSTLY_CLOUDY -> WeatherIcon.PartlyCloudy
        Forecast.STORM -> WeatherIcon.Wind
        Forecast.BROKEN_CLOUDS -> WeatherIcon.PartlyCloudy
        Forecast.HEAVY_THUNDERSTORM -> WeatherIcon.Thunder
        Forecast.HEAVY_THUNDERSTORM_WITH_RAIN -> WeatherIcon.Thunderstorm
        else -> WeatherIcon.Unknown
    }
}

@Composable
fun NoData() {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .wrapContentHeight(),
        verticalAlignment = Alignment.CenterVertically
    ) {
        Icon(
            painter = painterResource(R.drawable.light_mode_24px),
            contentDescription = "",
            modifier = Modifier
                .padding(24.dp)
                .size(32.dp),
            tint = MaterialTheme.colorScheme.secondary
        )
        Text(
            text = stringResource(id = R.string.weather_no_data),
            style = MaterialTheme.typography.bodySmall
        )
    }
}