/*
 * Copyright (C) 2026 SHX VPN
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 */

package org.strongswan.android.ui.compose

import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
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.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.KeyboardArrowRight
import androidx.compose.material.icons.rounded.Add
import androidx.compose.material.icons.rounded.ArrowDownward
import androidx.compose.material.icons.rounded.ArrowUpward
import androidx.compose.material.icons.rounded.Delete
import androidx.compose.material.icons.rounded.ExpandLess
import androidx.compose.material.icons.rounded.Language
import androidx.compose.material.icons.rounded.PlayArrow
import androidx.compose.material.icons.rounded.Schedule
import androidx.compose.material.icons.rounded.Edit
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
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.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import kotlinx.coroutines.flow.StateFlow
import org.strongswan.android.R
import org.strongswan.android.data.VpnProfile
import org.strongswan.android.logic.VpnStateService.ErrorState
import org.strongswan.android.logic.VpnStateService.State
import org.strongswan.android.ui.compose.theme.ConnectionCardRadius
import org.strongswan.android.ui.compose.theme.LocalShxStatusColors
import org.strongswan.android.ui.compose.theme.ScreenPadding

@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@Composable
fun HomeScreen(
	state: HomeUiState,
	trafficFlow: StateFlow<TrafficUi>,
	viewModel: HomeViewModel,
	onAddProfile: () -> Unit,
	onEditProfile: (VpnProfile) -> Unit,
	onShowLog: () -> Unit,
)
{
	val context = LocalContext.current
	/* collected here (not in ShxApp) so 500ms traffic ticks only recompose this screen */
	val traffic by trafficFlow.collectAsStateWithLifecycle()
	var pendingDelete by remember { mutableStateOf<VpnProfile?>(null) }
	var sheetProfile by remember { mutableStateOf<VpnProfile?>(null) }
	val connected = state.vpnState == State.CONNECTED
	val connecting = state.vpnState == State.CONNECTING || state.vpnState == State.DISCONNECTING
	val hasError = state.error != ErrorState.NO_ERROR
	val selected = state.selected
	val durationSec = if (connected) traffic.durationSec else 0L
	val status = LocalShxStatusColors.current
	val statusText = when
	{
		hasError -> stringResource(state.errorText)
		connected -> stringResource(R.string.status_protected)
		connecting && state.vpnState == State.DISCONNECTING -> stringResource(R.string.state_disconnecting)
		connecting -> stringResource(R.string.status_connecting)
		else -> stringResource(R.string.status_unprotected)
	}
	val statusColor = when
	{
		hasError -> MaterialTheme.colorScheme.error
		connected -> status.connected
		connecting -> status.connecting
		else -> status.disconnected
	}
	val subtitle = when
	{
		connected -> "${selected?.name ?: ""} · ${formatDuration(durationSec)}"
		connecting -> selected?.name ?: ""
		else -> stringResource(R.string.status_choose_profile)
	}

	Box(Modifier.fillMaxSize())
	{
		StatusGlowBackground(color = statusColor, active = connected || connecting)
		LazyColumn(
			modifier = Modifier.fillMaxSize(),
			horizontalAlignment = Alignment.CenterHorizontally,
		)
		{
			item(key = "status") {
				Column(
					modifier = Modifier
						.fillMaxWidth()
						.padding(top = 24.dp, bottom = 12.dp),
					horizontalAlignment = Alignment.CenterHorizontally,
				) {
					AnimatedContent(
						targetState = statusText,
						transitionSpec = { fadeIn(tween(220)) togetherWith fadeOut(tween(160)) },
						label = "statusText",
					) { text ->
						Text(
							text = text,
							style = MaterialTheme.typography.headlineMedium,
							fontWeight = FontWeight.SemiBold,
							color = statusColor,
						)
					}
					Spacer(Modifier.height(6.dp))
					Text(
						text = subtitle,
						style = MaterialTheme.typography.bodyMedium,
						color = MaterialTheme.colorScheme.onSurfaceVariant,
					)
				}
			}
			item(key = "card") {
				ConnectionCard(
					modifier = Modifier.padding(horizontal = ScreenPadding),
					profile = selected,
					vpnState = state.vpnState,
					traffic = traffic,
					enabled = selected != null && !selected.isReadOnly,
					onConnect = { selected?.let { viewModel.connect(context, it) } },
					onDisconnect = { viewModel.disconnect() },
					onCancel = { viewModel.disconnect() },
					onOpenDetails = { if (connected) viewModel.openDetails(true) else selected?.let { onEditProfile(it) } },
				)
			}
			if (hasError)
			{
				item(key = "error") {
					ErrorBanner(
						modifier = Modifier.padding(top = 12.dp, start = ScreenPadding, end = ScreenPadding),
						onRetry = { viewModel.reconnect() },
						onShowLog = onShowLog,
					)
				}
			}
			item(key = "header") {
				Row(
					modifier = Modifier
						.fillMaxWidth()
						.padding(top = 28.dp, bottom = 4.dp, start = ScreenPadding, end = 8.dp),
					verticalAlignment = Alignment.CenterVertically,
				) {
					Text(
						stringResource(R.string.profiles_title),
						style = MaterialTheme.typography.titleSmall,
						color = MaterialTheme.colorScheme.onSurfaceVariant,
						modifier = Modifier.weight(1f),
					)
					IconButton(onClick = onAddProfile) {
						Icon(Icons.Rounded.Add, contentDescription = stringResource(R.string.add_profile_cta))
					}
				}
			}
			if (state.profiles.isEmpty())
			{
				item(key = "empty") {
					EmptyProfiles(
						modifier = Modifier
							.fillMaxWidth()
							.padding(horizontal = ScreenPadding, vertical = 12.dp),
						onAdd = onAddProfile,
					)
				}
			}
			else
			{
				itemsIndexed(state.profiles, key = { _, p -> p.getUUID().toString() }) { index, profile ->
					val active = connected && profile.getUUID() == (state.activeProfile ?: selected)?.getUUID()
					ShxProfileRow(
						profile = profile,
						active = active,
						onClick = {
							viewModel.select(profile)
							viewModel.connect(context, profile)
						},
						onLongClick = { sheetProfile = profile },
					)
					if (index < state.profiles.lastIndex)
					{
						ShxDivider()
					}
				}
				item(key = "space") { Spacer(Modifier.height(24.dp)) }
			}
		}
	}

	if (state.detailsOpen)
	{
		ConnectionDetailsSheet(
			profile = state.activeProfile ?: state.selected,
			traffic = traffic,
			durationSec = durationSec,
			onDismiss = { viewModel.openDetails(false) },
			onDisconnect = {
				viewModel.openDetails(false)
				viewModel.disconnect()
			},
		)
	}

	sheetProfile?.let { profile ->
		ProfileActionsSheet(
			profile = profile,
			active = connected && profile.getUUID() == state.activeProfile?.getUUID(),
			onDismiss = { sheetProfile = null },
			onConnect = {
				sheetProfile = null
				viewModel.select(profile)
				viewModel.connect(context, profile)
			},
			onEdit = {
				sheetProfile = null
				onEditProfile(profile)
			},
			onDelete = {
				sheetProfile = null
				pendingDelete = profile
			},
		)
	}

	pendingDelete?.let { profile ->
		AlertDialog(
			onDismissRequest = { pendingDelete = null },
			title = { Text(stringResource(R.string.delete_profile)) },
			text = { Text(profile.name ?: "") },
			confirmButton = {
				TextButton(onClick = {
					viewModel.delete(profile)
					pendingDelete = null
				}) { Text(stringResource(R.string.delete_profile)) }
			},
			dismissButton = {
				TextButton(onClick = { pendingDelete = null }) {
					Text(stringResource(android.R.string.cancel))
				}
			},
		)
	}
}

@Composable
private fun StatusGlowBackground(color: Color, active: Boolean)
{
	val animated by animateColorAsState(color, label = "glow")
	val transition = rememberInfiniteTransition(label = "pulse")
	/* read inside the draw scope below so the pulse only invalidates drawing,
	 * instead of recomposing this composable on every frame */
	val pulse by transition.animateFloat(
		initialValue = 0.30f,
		targetValue = 0.55f,
		animationSpec = infiniteRepeatable(tween(1600, easing = LinearEasing), RepeatMode.Reverse),
		label = "a",
	)
	Canvas(Modifier.fillMaxSize())
	{
		val alpha = if (active) pulse else 0f
		val cx = size.width / 2f
		val cy = size.height * 0.16f
		drawCircle(
			brush = Brush.radialGradient(
				colors = listOf(animated.copy(alpha = alpha * 0.30f), Color.Transparent),
				center = Offset(cx, cy),
				radius = size.minDimension * 0.62f,
			),
			radius = size.minDimension * 0.62f,
			center = Offset(cx, cy),
		)
	}
}

@Composable
private fun ErrorBanner(modifier: Modifier = Modifier, onRetry: () -> Unit, onShowLog: () -> Unit)
{
	Surface(
		shape = MaterialTheme.shapes.medium,
		color = MaterialTheme.colorScheme.errorContainer,
		contentColor = MaterialTheme.colorScheme.onErrorContainer,
		modifier = modifier.fillMaxWidth(),
	) {
		Row(
			modifier = Modifier.padding(horizontal = 16.dp, vertical = 6.dp),
			verticalAlignment = Alignment.CenterVertically,
		) {
			Text(
				text = stringResource(R.string.connection_failed),
				style = MaterialTheme.typography.bodyMedium,
				modifier = Modifier.weight(1f),
				maxLines = 2,
			)
			TextButton(onClick = onRetry) { Text(stringResource(R.string.retry)) }
			TextButton(onClick = onShowLog) { Text(stringResource(R.string.show_log)) }
		}
	}
}

@Composable
private fun EmptyProfiles(modifier: Modifier = Modifier, onAdd: () -> Unit)
{
	Surface(
		shape = MaterialTheme.shapes.large,
		color = MaterialTheme.colorScheme.surfaceContainerLow,
		modifier = modifier,
	) {
		Column(
			modifier = Modifier
				.fillMaxWidth()
				.padding(24.dp),
			horizontalAlignment = Alignment.CenterHorizontally,
		) {
			Icon(
				Icons.Rounded.Language,
				contentDescription = null,
				tint = MaterialTheme.colorScheme.onSurfaceVariant,
				modifier = Modifier.size(40.dp),
			)
			Spacer(Modifier.height(12.dp))
			Text(
				stringResource(R.string.no_profiles),
				style = MaterialTheme.typography.bodyLarge,
				color = MaterialTheme.colorScheme.onSurfaceVariant,
			)
			Spacer(Modifier.height(16.dp))
			OutlinedButton(onClick = onAdd) {
				Icon(Icons.Rounded.Add, contentDescription = null, modifier = Modifier.size(18.dp))
				Spacer(Modifier.size(8.dp))
				Text(stringResource(R.string.add_profile_cta))
			}
		}
	}
}

@Composable
private fun TrafficStat(down: Boolean, total: Long, rate: Long)
{
	val label = if (down) stringResource(R.string.traffic_down) else stringResource(R.string.traffic_up)
	Row(
		verticalAlignment = Alignment.CenterVertically,
		horizontalArrangement = Arrangement.spacedBy(10.dp),
	)
	{
		Surface(
			shape = CircleShape,
			color = MaterialTheme.colorScheme.surfaceContainerHigh,
		) {
			Icon(
				imageVector = if (down) Icons.Rounded.ArrowDownward else Icons.Rounded.ArrowUpward,
				contentDescription = label,
				modifier = Modifier
					.padding(6.dp)
					.size(16.dp),
				tint = MaterialTheme.colorScheme.onSurfaceVariant,
			)
		}
		Column {
			Text(
				text = formatBytes(total),
				style = MaterialTheme.typography.titleSmall,
				fontWeight = FontWeight.Medium,
			)
			Text(
				text = formatRate(rate),
				style = MaterialTheme.typography.bodySmall,
				color = MaterialTheme.colorScheme.onSurfaceVariant,
			)
		}
	}
}

@Composable
private fun ConnectionCard(
	modifier: Modifier = Modifier,
	profile: VpnProfile?,
	vpnState: State,
	traffic: TrafficUi,
	enabled: Boolean,
	onConnect: () -> Unit,
	onDisconnect: () -> Unit,
	onCancel: () -> Unit,
	onOpenDetails: () -> Unit,
)
{
	val connecting = vpnState == State.CONNECTING || vpnState == State.DISCONNECTING
	val connected = vpnState == State.CONNECTED
	Surface(
		shape = MaterialTheme.shapes.large,
		color = MaterialTheme.colorScheme.surfaceContainerLow,
		border = androidx.compose.foundation.BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant),
		modifier = modifier.fillMaxWidth(),
	) {
		Column(Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp))
		{
			Row(
				modifier = Modifier
					.fillMaxWidth()
					.combinedClickable(enabled = profile != null, onClick = onOpenDetails),
				verticalAlignment = Alignment.CenterVertically,
			) {
				ProfileAvatar(icon = Icons.Rounded.Language, connected = connected)
				Column(
					modifier = Modifier
						.weight(1f)
						.padding(horizontal = 12.dp),
				) {
					Text(
						text = profile?.name ?: stringResource(R.string.no_profiles),
						style = MaterialTheme.typography.titleMedium.copy(fontSize = 18.sp),
						fontWeight = FontWeight.Medium,
						maxLines = 1,
					)
					Text(
						text = profile?.gateway ?: "",
						style = MaterialTheme.typography.bodySmall,
						color = MaterialTheme.colorScheme.onSurfaceVariant,
						maxLines = 1,
					)
				}
				Icon(
					Icons.Rounded.ExpandLess,
					contentDescription = stringResource(R.string.connection_details),
					tint = MaterialTheme.colorScheme.onSurfaceVariant,
				)
			}
			AnimatedVisibility(
				visible = connected,
				enter = expandVertically() + fadeIn(),
				exit = shrinkVertically() + fadeOut(),
			) {
				Row(
					Modifier.fillMaxWidth(),
					horizontalArrangement = Arrangement.SpaceEvenly,
					verticalAlignment = Alignment.CenterVertically,
				) {
					TrafficStat(down = true, total = traffic.bytesIn, rate = traffic.rateIn)
					Box(
						modifier = Modifier
							.size(1.dp, 32.dp)
							.background(MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.6f)),
					)
					TrafficStat(down = false, total = traffic.bytesOut, rate = traffic.rateOut)
				}
			}
			when (vpnState)
			{
				State.CONNECTED -> FilledTonalButton(
					onClick = onDisconnect,
					modifier = Modifier
						.fillMaxWidth()
						.height(48.dp),
					colors = ButtonDefaults.filledTonalButtonColors(
						containerColor = MaterialTheme.colorScheme.errorContainer,
						contentColor = MaterialTheme.colorScheme.onErrorContainer,
					),
					shape = MaterialTheme.shapes.medium,
				) { Text(stringResource(R.string.disconnect), fontSize = 16.sp) }
				State.CONNECTING, State.DISCONNECTING -> FilledTonalButton(
					onClick = onCancel,
					modifier = Modifier
						.fillMaxWidth()
						.height(48.dp),
					shape = MaterialTheme.shapes.medium,
				) {
					CircularProgressIndicator(Modifier.size(18.dp), strokeWidth = 2.dp)
					Spacer(Modifier.size(12.dp))
					Text(stringResource(android.R.string.cancel), fontSize = 16.sp)
				}
				else -> Button(
					onClick = onConnect,
					enabled = enabled,
					modifier = Modifier
						.fillMaxWidth()
						.height(48.dp),
					shape = MaterialTheme.shapes.medium,
				) { Text(stringResource(R.string.connect), fontSize = 16.sp) }
			}
		}
	}
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun ConnectionDetailsSheet(
	profile: VpnProfile?,
	traffic: TrafficUi,
	durationSec: Long,
	onDismiss: () -> Unit,
	onDisconnect: () -> Unit,
)
{
	ModalBottomSheet(
		onDismissRequest = onDismiss,
		sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true),
		containerColor = MaterialTheme.colorScheme.surfaceContainerLow,
	)
	{
		Column(Modifier.padding(horizontal = 24.dp))
		{
			Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(12.dp))
			{
				ProfileAvatar(icon = Icons.Rounded.Language, connected = true)
				Column {
					Text(
						profile?.name ?: "",
						style = MaterialTheme.typography.titleLarge,
						fontWeight = FontWeight.SemiBold,
					)
					Text(
						profile?.gateway ?: "",
						style = MaterialTheme.typography.bodySmall,
						color = MaterialTheme.colorScheme.onSurfaceVariant,
					)
				}
			}
			Spacer(Modifier.height(16.dp))
			DetailRow(icon = Icons.Rounded.Language, label = stringResource(R.string.profile_gateway_label), value = profile?.gateway ?: "—")
			DetailRow(icon = Icons.Rounded.Schedule, label = stringResource(R.string.duration_label), value = formatDuration(durationSec))
			DetailRow(
				icon = Icons.Rounded.ArrowDownward,
				label = stringResource(R.string.traffic_down),
				value = "${formatBytes(traffic.bytesIn)} · ${formatRate(traffic.rateIn)}",
			)
			DetailRow(
				icon = Icons.Rounded.ArrowUpward,
				label = stringResource(R.string.traffic_up),
				value = "${formatBytes(traffic.bytesOut)} · ${formatRate(traffic.rateOut)}",
			)
			Spacer(Modifier.height(24.dp))
			FilledTonalButton(
				onClick = onDisconnect,
				colors = ButtonDefaults.filledTonalButtonColors(
					containerColor = MaterialTheme.colorScheme.errorContainer,
					contentColor = MaterialTheme.colorScheme.onErrorContainer,
				),
				shape = MaterialTheme.shapes.medium,
				modifier = Modifier.fillMaxWidth(),
			) {
				Text(stringResource(R.string.disconnect))
			}
			Spacer(Modifier.height(32.dp))
		}
	}
}

@Composable
private fun DetailRow(icon: ImageVector, label: String, value: String)
{
	ListItem(
		leadingContent = {
			Surface(
				shape = CircleShape,
				color = MaterialTheme.colorScheme.surfaceContainerHigh,
			) {
				Icon(
					icon,
					contentDescription = null,
					modifier = Modifier
						.padding(8.dp)
						.size(18.dp),
					tint = MaterialTheme.colorScheme.onSurfaceVariant,
				)
			}
		},
		headlineContent = { Text(label) },
		supportingContent = { Text(value) },
	)
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ProfileActionsSheet(
	profile: VpnProfile,
	active: Boolean,
	onDismiss: () -> Unit,
	onConnect: () -> Unit,
	onEdit: () -> Unit,
	onDelete: () -> Unit,
)
{
	ModalBottomSheet(
		onDismissRequest = onDismiss,
		sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true),
		containerColor = MaterialTheme.colorScheme.surfaceContainerLow,
	)
	{
		Column(Modifier.fillMaxWidth())
		{
			ShxProfileRow(profile = profile, active = active, onClick = {}, onLongClick = {})
			ShxDivider(indent = false)
			SheetAction(icon = Icons.Rounded.PlayArrow, label = stringResource(R.string.connect), onClick = onConnect)
			ShxDivider(indent = false)
			SheetAction(icon = Icons.Rounded.Edit, label = stringResource(R.string.edit_profile), onClick = onEdit)
			ShxDivider(indent = false)
			SheetAction(
				icon = Icons.Rounded.Delete,
				label = stringResource(R.string.delete_profile),
				tint = MaterialTheme.colorScheme.error,
				onClick = onDelete,
			)
			Spacer(Modifier.height(24.dp))
		}
	}
}

@Composable
private fun SheetAction(icon: ImageVector, label: String, onClick: () -> Unit, tint: Color = Color.Unspecified)
{
	Row(
		verticalAlignment = Alignment.CenterVertically,
		modifier = Modifier
			.fillMaxWidth()
			.combinedClickable(onClick = onClick)
			.padding(horizontal = 24.dp, vertical = 16.dp),
	)
	{
		Icon(icon, contentDescription = null, tint = tint, modifier = Modifier.size(22.dp))
		Spacer(Modifier.size(16.dp))
		Text(label, style = MaterialTheme.typography.bodyLarge)
	}
}
