package net.buzzert.kordophonedroid.ui.conversationlist

import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
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.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Divider
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Settings
import androidx.compose.material.pullrefresh.PullRefreshIndicator
import androidx.compose.material.pullrefresh.pullRefresh
import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import kotlinx.coroutines.launch
import net.buzzert.kordophone.backend.model.Conversation
import net.buzzert.kordophonedroid.R
import net.buzzert.kordophonedroid.ui.Destination
import net.buzzert.kordophonedroid.ui.LocalNavController
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.util.Date

fun formatDateTime(dateTime: LocalDateTime): String {
    val formatter: DateTimeFormatter = if (LocalDate.now().isEqual(dateTime.toLocalDate())) {
        DateTimeFormatter.ofPattern("HH:mm") // show just the time
    } else {
        DateTimeFormatter.ofPattern("M/d/yy") // show day/month/year
    }

    return dateTime.format(formatter)
}

@Composable
fun ConversationListScreen(
    viewModel: ConversationListViewModel = hiltViewModel(),
) {
    val conversations by viewModel.conversations.collectAsStateWithLifecycle(initialValue = emptyList())
    val encounteredError by viewModel.encounteredConnectionError

    ConversationListView(
        conversations = conversations,
        isConfigured = viewModel.isServerConfigured,
        encounteredError = encounteredError,
        onRefresh = suspend { viewModel.refresh() }
    )
}

@Composable
@OptIn(ExperimentalMaterialApi::class)
fun ConversationListView(
    conversations: List<Conversation>,
    isConfigured: Boolean = true,
    encounteredError: Boolean = false,
    onRefresh: suspend () -> Unit,
) {
    val listState = rememberLazyListState()

    val refreshScope = rememberCoroutineScope()
    var refreshing by remember { mutableStateOf(false) }

    fun refresh() = refreshScope.launch {
        refreshing = true
        onRefresh()
        refreshing = false
    }

    val showErrorScreen = conversations.isEmpty() && encounteredError

    val refreshState = rememberPullRefreshState(refreshing = refreshing, onRefresh = ::refresh)

    val navController = LocalNavController.current
    val onSettingsInvoked = { navController.navigate(Destination.Settings.route) }
    Scaffold(
        topBar = {
            TopAppBar(title = { Text("Conversations") }, actions = {
                IconButton(onClick = onSettingsInvoked) {
                    Icon(Icons.Rounded.Settings, contentDescription = "Settings")
                }
            })
        }
    ) {
        if (showErrorScreen) {
            NoContentView(
                icon = R.drawable.error,
                text = "Connection error",
                onSettings = onSettingsInvoked
            )
        } else if (!isConfigured) {
            NoContentView(
                icon = R.drawable.storage,
                text = "Server not configured",
                onSettings = onSettingsInvoked
            )
        } else {
            Box(Modifier.pullRefresh(refreshState)) {
                LazyColumn(
                    state = listState,
                    modifier = Modifier
                        .padding(it)
                        .fillMaxSize()
                ) {
                    items(conversations) { conversation ->
                        val clickHandler = {
                            val route = Destination.MessageList.createRoute(conversation.guid)
                            navController.navigate(route)
                        }

                        ConversationListItem(
                            name = conversation.formattedDisplayName(),
                            id = conversation.guid,
                            isUnread = conversation.unreadCount > 0,
                            lastMessagePreview = conversation.lastMessagePreview ?: "",
                            date = conversation.date,
                            onClick = clickHandler
                        )
                    }
                }

                PullRefreshIndicator(
                    refreshing = refreshing,
                    state = refreshState,
                    modifier = Modifier.align(Alignment.TopCenter),
                )
            }
        }
    }
}

@Composable
fun ConversationListItem(
    name: String,
    id: String,
    isUnread: Boolean,
    lastMessagePreview: String,
    date: Date,
    onClick: () -> Unit
) {
    val unreadSize = 12.dp
    val horizontalPadding = 8.dp
    val verticalPadding = 14.dp

    Row(
        Modifier
            .clickable(onClick = onClick)
    ) {
        Spacer(Modifier.width(horizontalPadding))

        // Unread icon
        if (isUnread) {
            UnreadIndicator(
                size = unreadSize,
                modifier = Modifier.align(Alignment.CenterVertically)
            )
        } else {
            Spacer(modifier = Modifier.size(unreadSize))
        }

        Spacer(Modifier.width(horizontalPadding))

        Column {
            Spacer(Modifier.height(verticalPadding))
            Row(
                horizontalArrangement = Arrangement.SpaceBetween,
                modifier = Modifier.fillMaxWidth()
            ) {
                Text(
                    name,
                    style = TextStyle(fontSize = 18.sp, fontWeight = FontWeight.Bold),
                    overflow = TextOverflow.Ellipsis,
                    maxLines = 1,
                    modifier = Modifier.weight(1f, fill = true)
                )

                Spacer(modifier = Modifier)

                Text(
                    formatDateTime(
                        date.toInstant()
                            .atZone(ZoneId.systemDefault())
                            .toLocalDateTime()
                    ),
                    color = MaterialTheme.colors.onBackground.copy(alpha = 0.4f),
                    maxLines = 1,
                    modifier = Modifier
                        .align(Alignment.CenterVertically)
                    ,
                )

                Spacer(Modifier.width(horizontalPadding))
            }

            Text(lastMessagePreview, maxLines = 1, overflow = TextOverflow.Ellipsis)

            Spacer(Modifier.height(verticalPadding))
            Divider()
        }
    }
}

@Composable
fun UnreadIndicator(size: Dp, modifier: Modifier = Modifier) {
    Box(
        modifier = modifier
            .size(size)
            .background(
                color = MaterialTheme.colors.primary,
                shape = CircleShape
            )
    )
}

