/*
 * 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */

package org.strongswan.android.ui.compose

import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.provider.Settings
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.clickable
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.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
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.Delete
import androidx.compose.material.icons.rounded.Language
import androidx.compose.material.icons.rounded.Wifi
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
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.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.compose.LocalLifecycleOwner
import org.strongswan.android.R
import org.strongswan.android.data.VpnProfile
import org.strongswan.android.logic.autoconnect.AutoConnectManager
import org.strongswan.android.ui.compose.theme.ScreenPadding

/**
 * Trusted networks settings: when enabled, the VPN is started on cellular and untrusted
 * Wi-Fi, and auto sessions are stopped on trusted Wi-Fi.
 */
@Composable
fun TrustedNetworksScreen(
	profiles: List<VpnProfile>,
	currentSsid: String?,
)
{
	val context = LocalContext.current
	val manager = remember { AutoConnectManager.getInstance(context) }
	var config by remember { mutableStateOf(manager.currentConfig) }
	var showProfilePicker by remember { mutableStateOf(false) }
	var showAddSsid by remember { mutableStateOf(false) }
	var pendingDeleteSsid by remember { mutableStateOf<String?>(null) }
	var hasBackgroundLocation by remember { mutableStateOf(isBackgroundLocationGranted(context)) }
	var askedBackground by remember { mutableStateOf(false) }
	val lifecycleOwner = LocalLifecycleOwner.current

	fun refreshPermissions()
	{
		hasBackgroundLocation = isBackgroundLocationGranted(context)
		if (isFineLocationGranted(context))
		{
			manager.reloadConfig()
		}
	}

	val requestBackground = rememberLauncherForActivityResult(
		ActivityResultContracts.RequestPermission()
	) { refreshPermissions() }
	val requestForeground = rememberLauncherForActivityResult(
		ActivityResultContracts.RequestMultiplePermissions()
	) {
		refreshPermissions()
		if (isFineLocationGranted(context) && !isBackgroundLocationGranted(context) &&
			Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
		{
			askedBackground = true
			requestBackground.launch(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
		}
	}

	fun requestSsidPermissions()
	{
		if (!isFineLocationGranted(context))
		{
			requestForeground.launch(wifiSsidPermissions())
			return
		}
		if (!isBackgroundLocationGranted(context) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
		{
			if (askedBackground)
			{
				openAppDetails(context)
				return
			}
			askedBackground = true
			requestBackground.launch(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
		}
	}

	DisposableEffect(lifecycleOwner)
	{
		val observer = LifecycleEventObserver { _, event ->
			if (event == Lifecycle.Event.ON_RESUME)
			{
				refreshPermissions()
			}
		}
		lifecycleOwner.lifecycle.addObserver(observer)
		onDispose { lifecycleOwner.lifecycle.removeObserver(observer) }
	}
	val selectedProfile = profiles.firstOrNull { it.getUUID().toString() == config.profileUuid }
	val enabled = config.enabled

	fun update(transform: (AutoConnectManager.Config) -> AutoConnectManager.Config)
	{
		val updated = transform(config)
		manager.updateConfig { updated }
		config = updated
	}

	Column(
		Modifier
			.fillMaxSize()
			.verticalScroll(rememberScrollState())
			.padding(bottom = 24.dp),
	)
	{
		TrustedSection(title = stringResource(R.string.settings_section_general))
		{
			TrustedToggleRow(
				icon = Icons.Rounded.Wifi,
				title = stringResource(R.string.auto_connect_title),
				subtitle = stringResource(R.string.auto_connect_summary),
				checked = enabled,
				onCheckedChange = { checked ->
					if (checked)
					{
						requestSsidPermissions()
					}
					update { it.copy(enabled = checked) }
				},
			)
			TrustedDivider()
			TrustedRow(
				icon = Icons.Rounded.Language,
				title = stringResource(R.string.auto_connect_profile),
				subtitle = selectedProfile?.name
					?: stringResource(R.string.auto_connect_profile_none),
				enabled = enabled,
				onClick = { showProfilePicker = true },
			)
		}

		if (enabled && !hasBackgroundLocation)
		{
			Spacer(Modifier.size(12.dp))
			Surface(
				shape = MaterialTheme.shapes.large,
				color = MaterialTheme.colorScheme.errorContainer,
				modifier = Modifier
					.fillMaxWidth()
					.padding(horizontal = ScreenPadding)
					.clickable { requestSsidPermissions() },
			)
			{
				Row(
					verticalAlignment = Alignment.CenterVertically,
					modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp),
				)
				{
					Text(
						text = stringResource(R.string.auto_connect_location_banner),
						style = MaterialTheme.typography.bodySmall,
						color = MaterialTheme.colorScheme.onErrorContainer,
						modifier = Modifier.weight(1f),
					)
					TextButton(onClick = { requestSsidPermissions() }) {
						Text(stringResource(R.string.auto_connect_location_grant))
					}
				}
			}
		}

		TrustedSection(title = stringResource(R.string.auto_connect_trusted_title))
		{
			Text(
				text = stringResource(R.string.auto_connect_trusted_hint),
				style = MaterialTheme.typography.bodySmall,
				color = MaterialTheme.colorScheme.onSurfaceVariant,
				modifier = Modifier
					.fillMaxWidth()
					.padding(horizontal = 16.dp, vertical = 8.dp),
			)
			if (config.trustedSsids.isEmpty())
			{
				Text(
					text = stringResource(R.string.auto_connect_no_networks),
					style = MaterialTheme.typography.bodyMedium,
					color = MaterialTheme.colorScheme.onSurfaceVariant,
					modifier = Modifier
						.fillMaxWidth()
						.padding(horizontal = 16.dp, vertical = 14.dp),
				)
			}
		else
		{
			val sortedSsids = remember(config.trustedSsids) { config.trustedSsids.sorted() }
			sortedSsids.forEachIndexed { index, ssid ->
					if (index > 0)
					{
						TrustedDivider()
					}
					Row(
						verticalAlignment = Alignment.CenterVertically,
						modifier = Modifier
							.fillMaxWidth()
							.padding(horizontal = 16.dp),
					)
					{
						Icon(
							Icons.Rounded.Wifi,
							contentDescription = null,
							tint = MaterialTheme.colorScheme.onSurfaceVariant,
							modifier = Modifier.size(20.dp),
						)
						Text(
							text = ssid,
							style = MaterialTheme.typography.bodyLarge,
							modifier = Modifier
								.weight(1f)
								.padding(horizontal = 16.dp, vertical = 14.dp),
						)
						IconButton(onClick = { pendingDeleteSsid = ssid }) {
							Icon(
								Icons.Rounded.Delete,
								contentDescription = stringResource(R.string.delete_profile),
								tint = MaterialTheme.colorScheme.error,
							)
						}
					}
				}
			}
			TrustedDivider()
			TrustedAddNetworkRow(
				currentSsid = currentSsid,
				onAddCurrent = { ssid -> update { it.copy(trustedSsids = it.trustedSsids + ssid) } },
				onAddManual = { showAddSsid = true },
			)
		}
	}

	if (showProfilePicker)
	{
		AlertDialog(
			onDismissRequest = { showProfilePicker = false },
			title = { Text(stringResource(R.string.auto_connect_profile)) },
			text = {
				Column {
					profiles.forEach { profile ->
						Row(
							verticalAlignment = Alignment.CenterVertically,
							modifier = Modifier
								.fillMaxWidth()
								.clickable {
									update { it.copy(profileUuid = profile.getUUID().toString()) }
									showProfilePicker = false
								}
								.padding(vertical = 10.dp),
						)
						{
							RadioButton(
								selected = config.profileUuid == profile.getUUID().toString(),
								onClick = null,
							)
							Text(profile.name ?: "", modifier = Modifier.padding(start = 12.dp))
						}
					}
				}
			},
			confirmButton = {
				TextButton(onClick = { showProfilePicker = false }) {
					Text(stringResource(android.R.string.cancel))
				}
			},
		)
	}

	if (showAddSsid)
	{
		var ssid by remember { mutableStateOf("") }
		AlertDialog(
			onDismissRequest = { showAddSsid = false },
			title = { Text(stringResource(R.string.auto_connect_add_network)) },
			text = {
				OutlinedTextField(
					value = ssid,
					onValueChange = { ssid = it },
					singleLine = true,
					label = { Text(stringResource(R.string.auto_connect_ssid_label)) },
				)
			},
			confirmButton = {
				TextButton(
					onClick = {
						val trimmed = ssid.trim()
						if (trimmed.isNotEmpty())
						{
							update { it.copy(trustedSsids = it.trustedSsids + trimmed) }
						}
						showAddSsid = false
					},
					enabled = ssid.isNotBlank(),
				) { Text(stringResource(R.string.add_profile_cta)) }
			},
			dismissButton = {
				TextButton(onClick = { showAddSsid = false }) {
					Text(stringResource(android.R.string.cancel))
				}
			},
		)
	}

	pendingDeleteSsid?.let { ssid ->
		AlertDialog(
			onDismissRequest = { pendingDeleteSsid = null },
			title = { Text(stringResource(R.string.auto_connect_remove_network)) },
			text = { Text(ssid) },
			confirmButton = {
				TextButton(onClick = {
					update { it.copy(trustedSsids = it.trustedSsids - ssid) }
					pendingDeleteSsid = null
				}) { Text(stringResource(R.string.delete_profile), color = MaterialTheme.colorScheme.error) }
			},
			dismissButton = {
				TextButton(onClick = { pendingDeleteSsid = null }) {
					Text(stringResource(android.R.string.cancel))
				}
			},
		)
	}
}

@Composable
private fun TrustedSection(title: String, content: @Composable () -> Unit)
{
	Text(
		text = title.uppercase(),
		style = MaterialTheme.typography.labelMedium,
		color = MaterialTheme.colorScheme.onSurfaceVariant,
		modifier = Modifier
			.fillMaxWidth()
			.padding(start = ScreenPadding + 16.dp, top = 20.dp, bottom = 8.dp),
	)
	Surface(
		shape = MaterialTheme.shapes.large,
		color = MaterialTheme.colorScheme.surfaceContainerLow,
		modifier = Modifier
			.fillMaxWidth()
			.padding(horizontal = ScreenPadding),
	)
	{
		Column { content() }
	}
}

@Composable
private fun TrustedDivider()
{
	HorizontalDivider(
		color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.6f),
		modifier = Modifier.padding(start = 52.dp),
	)
}

@Composable
private fun TrustedIconWrapper(icon: ImageVector)
{
	Surface(
		shape = MaterialTheme.shapes.small,
		color = MaterialTheme.colorScheme.primaryContainer,
		modifier = Modifier.size(36.dp),
	)
	{
		Icon(
			imageVector = icon,
			contentDescription = null,
			tint = MaterialTheme.colorScheme.primary,
			modifier = Modifier
				.padding(8.dp)
				.size(20.dp),
		)
	}
}

@Composable
private fun TrustedToggleRow(
	icon: ImageVector,
	title: String,
	subtitle: String,
	checked: Boolean,
	onCheckedChange: (Boolean) -> Unit,
)
{
	Row(
		verticalAlignment = Alignment.CenterVertically,
		modifier = Modifier
			.fillMaxWidth()
			.padding(horizontal = 16.dp, vertical = 14.dp),
	)
	{
		TrustedIconWrapper(icon = icon)
		Column(
			modifier = Modifier
				.weight(1f)
				.padding(horizontal = 16.dp),
		)
		{
			Text(title, style = MaterialTheme.typography.bodyLarge)
			Text(
				subtitle,
				style = MaterialTheme.typography.bodySmall,
				color = MaterialTheme.colorScheme.onSurfaceVariant,
			)
		}
		Switch(checked = checked, onCheckedChange = onCheckedChange)
	}
}

@Composable
private fun TrustedRow(
	icon: ImageVector,
	title: String,
	subtitle: String,
	enabled: Boolean,
	onClick: () -> Unit,
)
{
	Row(
		verticalAlignment = Alignment.CenterVertically,
		modifier = Modifier
			.fillMaxWidth()
			.clickable(enabled = enabled, onClick = onClick)
			.padding(horizontal = 16.dp, vertical = 14.dp),
	)
	{
		TrustedIconWrapper(icon = icon)
		Column(
			modifier = Modifier
				.weight(1f)
				.padding(horizontal = 16.dp),
		)
		{
			Text(title, style = MaterialTheme.typography.bodyLarge)
			Text(
				subtitle,
				style = MaterialTheme.typography.bodySmall,
				color = MaterialTheme.colorScheme.onSurfaceVariant,
			)
		}
		Icon(
			Icons.AutoMirrored.Rounded.KeyboardArrowRight,
			contentDescription = null,
			tint = MaterialTheme.colorScheme.onSurfaceVariant,
		)
	}
}

@Composable
private fun TrustedAddNetworkRow(
	currentSsid: String?,
	onAddCurrent: (String) -> Unit,
	onAddManual: () -> Unit,
)
{
	Row(
		verticalAlignment = Alignment.CenterVertically,
		horizontalArrangement = androidx.compose.foundation.layout.Arrangement.Center,
		modifier = Modifier
			.fillMaxWidth()
			.padding(horizontal = 16.dp, vertical = 6.dp),
	)
	{
		if (currentSsid != null)
		{
			TextButton(onClick = { onAddCurrent(currentSsid) })
			{
				Icon(Icons.Rounded.Add, contentDescription = null, modifier = Modifier.size(18.dp))
				Spacer(Modifier.size(8.dp))
				Text(stringResource(R.string.auto_connect_add_current, currentSsid))
			}
		}
		else
		{
			TextButton(onClick = onAddManual)
			{
				Icon(Icons.Rounded.Add, contentDescription = null, modifier = Modifier.size(18.dp))
				Spacer(Modifier.size(8.dp))
				Text(stringResource(R.string.auto_connect_add_network))
			}
		}
	}
}

private fun isFineLocationGranted(context: Context): Boolean =
	ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) ==
		PackageManager.PERMISSION_GRANTED

private fun isBackgroundLocationGranted(context: Context): Boolean
{
	if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
	{
		return true
	}
	return ContextCompat.checkSelfPermission(
		context, Manifest.permission.ACCESS_BACKGROUND_LOCATION
	) == PackageManager.PERMISSION_GRANTED
}

private fun wifiSsidPermissions(): Array<String> = buildList {
	add(Manifest.permission.ACCESS_FINE_LOCATION)
	if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
	{
		add(Manifest.permission.NEARBY_WIFI_DEVICES)
	}
}.toTypedArray()

private fun openAppDetails(context: Context)
{
	context.startActivity(
		Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
			data = Uri.fromParts("package", context.packageName, null)
		}
	)
}
