/*
 * 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 android.app.Activity
import android.content.Intent
import android.security.KeyChain
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.ExpandMore
import androidx.compose.material.icons.filled.Visibility
import androidx.compose.material.icons.filled.VisibilityOff
import androidx.compose.material3.Button
import androidx.compose.material3.Checkbox
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuAnchorType
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.ListItemDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringArrayResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import org.strongswan.android.R
import org.strongswan.android.data.VpnProfile
import org.strongswan.android.data.VpnProfile.SelectedAppsHandling
import org.strongswan.android.data.VpnProfileDataSource
import org.strongswan.android.data.VpnType
import org.strongswan.android.data.VpnType.VpnTypeFeature
import org.strongswan.android.ui.SelectedApplicationsActivity
import org.strongswan.android.ui.TrustedCertificatesActivity
import org.strongswan.android.utils.Constants
import org.strongswan.android.utils.IPRangeSet
import org.strongswan.android.utils.Utils
import java.util.TreeSet

data class ProfileFormState(
	val name: String = "",
	val gateway: String = "",
	val vpnType: VpnType = VpnType.IKEV2_EAP,
	val username: String = "",
	val password: String = "",
	val caAuto: Boolean = true,
	val caAlias: String? = null,
	val caLabel: String = "",
	val userCertAlias: String? = null,
	val remoteId: String = "",
	val localId: String = "",
	val dns: String = "",
	val mtu: String = "",
	val port: String = "",
	val natKeepalive: String = "",
	val certReq: Boolean = true,
	val useOcsp: Boolean = true,
	val useCrl: Boolean = true,
	val strictRevocation: Boolean = false,
	val rsaPss: Boolean = false,
	val ipv6Transport: Boolean = false,
	val includedSubnets: String = "",
	val excludedSubnets: String = "",
	val blockIpv4: Boolean = false,
	val blockIpv6: Boolean = false,
	val appsHandling: SelectedAppsHandling = SelectedAppsHandling.SELECTED_APPS_DISABLE,
	val selectedApps: Set<String> = emptySet(),
	val ikeProposal: String = "",
	val espProposal: String = "",
	val proxyHost: String = "",
	val proxyPort: String = "",
	val proxyExclusions: String = "",
	val readOnly: Boolean = false,
	val gatewayError: String? = null,
	val usernameError: String? = null,
	val advanced: Boolean = false,
)

fun ProfileFormState.toProfile(existing: VpnProfile?): VpnProfile
{
	val profile = existing ?: VpnProfile()
	val gw = gateway.trim()
	profile.name = name.trim().ifEmpty { gw }
	profile.gateway = gw
	profile.vpnType = vpnType
	if (vpnType.has(VpnTypeFeature.USER_PASS))
	{
		profile.username = username.trim().ifEmpty { null }
		profile.password = password.ifEmpty { null }
	}
	if (vpnType.has(VpnTypeFeature.CERTIFICATE))
	{
		profile.userCertificateAlias = userCertAlias
	}
	profile.certificateAlias = if (caAuto) null else caAlias
	profile.remoteId = remoteId.trim().ifEmpty { null }
	profile.localId = localId.trim().ifEmpty { null }
	profile.dnsServers = dns.trim().ifEmpty { null }
	profile.setMTU(mtu.trim().toIntOrNull())
	profile.port = port.trim().toIntOrNull()
	profile.setNATKeepAlive(natKeepalive.trim().toIntOrNull())
	var flags = 0
	if (!certReq) flags = flags or VpnProfile.FLAGS_SUPPRESS_CERT_REQS
	if (!useCrl) flags = flags or VpnProfile.FLAGS_DISABLE_CRL
	if (!useOcsp) flags = flags or VpnProfile.FLAGS_DISABLE_OCSP
	if (strictRevocation) flags = flags or VpnProfile.FLAGS_STRICT_REVOCATION
	if (rsaPss) flags = flags or VpnProfile.FLAGS_RSA_PSS
	if (ipv6Transport) flags = flags or VpnProfile.FLAGS_IPv6_TRANSPORT
	profile.flags = flags
	profile.includedSubnets = includedSubnets.trim().ifEmpty { null }
	profile.excludedSubnets = excludedSubnets.trim().ifEmpty { null }
	var st = 0
	if (blockIpv4) st = st or VpnProfile.SPLIT_TUNNELING_BLOCK_IPV4
	if (blockIpv6) st = st or VpnProfile.SPLIT_TUNNELING_BLOCK_IPV6
	profile.splitTunneling = if (st == 0) null else st
	profile.selectedAppsHandling = appsHandling
	profile.setSelectedApps(TreeSet(selectedApps))
	profile.ikeProposal = ikeProposal.trim().ifEmpty { null }
	profile.espProposal = espProposal.trim().ifEmpty { null }
	profile.proxyHost = proxyHost.trim().ifEmpty { null }
	profile.proxyPort = proxyPort.trim().toIntOrNull()
	profile.proxyExclusions = proxyExclusions.trim().ifEmpty { null }
	return profile
}

fun VpnProfile.toFormState(): ProfileFormState
{
	val flags = flags ?: 0
	val st = splitTunneling ?: 0
	return ProfileFormState(
		name = name ?: "",
		gateway = gateway ?: "",
		vpnType = vpnType ?: VpnType.IKEV2_EAP,
		username = username ?: "",
		password = password ?: "",
		caAuto = certificateAlias == null,
		caAlias = certificateAlias,
		caLabel = certificateAlias ?: "",
		userCertAlias = userCertificateAlias,
		remoteId = remoteId ?: "",
		localId = localId ?: "",
		dns = dnsServers ?: "",
		mtu = getMTU()?.toString() ?: "",
		port = port?.toString() ?: "",
		natKeepalive = getNATKeepAlive()?.toString() ?: "",
		certReq = flags and VpnProfile.FLAGS_SUPPRESS_CERT_REQS == 0,
		useCrl = flags and VpnProfile.FLAGS_DISABLE_CRL == 0,
		useOcsp = flags and VpnProfile.FLAGS_DISABLE_OCSP == 0,
		strictRevocation = flags and VpnProfile.FLAGS_STRICT_REVOCATION != 0,
		rsaPss = flags and VpnProfile.FLAGS_RSA_PSS != 0,
		ipv6Transport = flags and VpnProfile.FLAGS_IPv6_TRANSPORT != 0,
		includedSubnets = includedSubnets ?: "",
		excludedSubnets = excludedSubnets ?: "",
		blockIpv4 = st and VpnProfile.SPLIT_TUNNELING_BLOCK_IPV4 != 0,
		blockIpv6 = st and VpnProfile.SPLIT_TUNNELING_BLOCK_IPV6 != 0,
		appsHandling = selectedAppsHandling,
		selectedApps = selectedAppsSet ?: emptySet(),
		ikeProposal = ikeProposal ?: "",
		espProposal = espProposal ?: "",
		proxyHost = proxyHost ?: "",
		proxyPort = proxyPort?.toString() ?: "",
		proxyExclusions = proxyExclusions ?: "",
		readOnly = isReadOnly,
		advanced = remoteId != null || localId != null || dnsServers != null || getMTU() != null
			|| port != null || getNATKeepAlive() != null || flags != 0 || st != 0
			|| includedSubnets != null || excludedSubnets != null
			|| selectedAppsHandling != SelectedAppsHandling.SELECTED_APPS_DISABLE
			|| ikeProposal != null || espProposal != null || proxyHost != null,
	)
}

fun ProfileFormState.validate(ctx: android.content.Context): ProfileFormState
{
	var next = this.copy(gatewayError = null, usernameError = null)
	if (gateway.isBlank())
	{
		next = next.copy(gatewayError = ctx.getString(R.string.alert_text_no_input_gateway))
	}
	if (vpnType.has(VpnTypeFeature.USER_PASS) && username.isBlank())
	{
		next = next.copy(usernameError = ctx.getString(R.string.alert_text_no_input_username))
	}
	if (vpnType.has(VpnTypeFeature.CERTIFICATE) && userCertAlias.isNullOrBlank())
	{
		next = next.copy(usernameError = ctx.getString(R.string.alert_text_nocertfound_title))
	}
	val mtuVal = mtu.trim().toIntOrNull()
	if (mtu.isNotBlank() && (mtuVal == null || mtuVal < Constants.MTU_MIN || mtuVal > Constants.MTU_MAX))
	{
		next = next.copy(gatewayError = next.gatewayError ?: ctx.getString(R.string.alert_text_out_of_range, Constants.MTU_MIN, Constants.MTU_MAX))
	}
	if (includedSubnets.isNotBlank())
	{
		try { IPRangeSet.fromString(includedSubnets) } catch (_: Exception) {
			next = next.copy(advanced = true)
		}
	}
	if (ikeProposal.isNotBlank() && !Utils.isProposalValid(true, ikeProposal))
	{
		next = next.copy(advanced = true)
	}
	if (espProposal.isNotBlank() && !Utils.isProposalValid(false, espProposal))
	{
		next = next.copy(advanced = true)
	}
	return next
}

fun ProfileFormState.isValid(): Boolean
{
	if (gateway.isBlank()) return false
	if (vpnType.has(VpnTypeFeature.USER_PASS) && username.isBlank()) return false
	if (vpnType.has(VpnTypeFeature.CERTIFICATE) && userCertAlias.isNullOrBlank()) return false
	if (!caAuto && caAlias.isNullOrBlank()) return false
	return true
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ProfileFormScreen(
	title: String,
	state: ProfileFormState,
	onChange: (ProfileFormState) -> Unit,
	onSave: () -> Unit,
	onCancel: () -> Unit,
)
{
	val context = LocalContext.current
	val types = stringArrayResource(R.array.vpn_types)
	val appsHandling = stringArrayResource(R.array.apps_handling)
	var typeExpanded by remember { mutableStateOf(false) }
	var appsExpanded by remember { mutableStateOf(false) }
	var showPassword by remember { mutableStateOf(false) }
	val enabled = !state.readOnly

	val latest = rememberUpdatedState(state)
	val pickCa = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
		if (result.resultCode == Activity.RESULT_OK)
		{
			val alias = result.data?.getStringExtra(VpnProfileDataSource.KEY_CERTIFICATE)
			onChange(latest.value.copy(caAlias = alias, caLabel = alias ?: "", caAuto = alias == null))
		}
	}
	val pickApps = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
		if (result.resultCode == Activity.RESULT_OK)
		{
			val list = result.data?.getStringArrayListExtra(VpnProfileDataSource.KEY_SELECTED_APPS_LIST) ?: arrayListOf()
			onChange(latest.value.copy(selectedApps = list.toSet()))
		}
	}

	Scaffold(
		modifier = Modifier.windowInsetsPadding(
			WindowInsets.safeDrawing.only(WindowInsetsSides.Bottom),
		),
		contentWindowInsets = WindowInsets.safeDrawing.only(
			WindowInsetsSides.Horizontal + WindowInsetsSides.Top,
		),
		topBar = {
			TopAppBar(
				title = { Text(title, maxLines = 1) },
				navigationIcon = {
					IconButton(onClick = onCancel) {
						Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
					}
				},
				colors = TopAppBarDefaults.topAppBarColors(
					containerColor = MaterialTheme.colorScheme.background,
				),
			)
		},
		bottomBar = {
			if (enabled)
			{
				Surface(
					color = MaterialTheme.colorScheme.background,
					tonalElevation = 0.dp,
					modifier = Modifier.windowInsetsPadding(
						WindowInsets.safeDrawing.only(WindowInsetsSides.Bottom),
					),
				)
				{
					Row(
						modifier = Modifier
							.fillMaxWidth()
							.padding(horizontal = 20.dp, vertical = 12.dp),
						horizontalArrangement = Arrangement.spacedBy(12.dp),
					) {
						OutlinedButton(
							onClick = onCancel,
							shape = MaterialTheme.shapes.medium,
							modifier = Modifier
								.weight(1f)
								.height(48.dp),
						) { Text(stringResource(R.string.profile_edit_cancel)) }
						Button(
							onClick = onSave,
							shape = MaterialTheme.shapes.medium,
							modifier = Modifier
								.weight(2f)
								.height(48.dp),
						) { Text(stringResource(R.string.profile_edit_save)) }
					}
				}
			}
		},
	) { padding ->
		Column(
			Modifier
				.fillMaxSize()
				.padding(padding)
				.verticalScroll(rememberScrollState())
				.padding(20.dp),
			verticalArrangement = Arrangement.spacedBy(14.dp),
		)
		{
			if (state.readOnly)
			{
				Text(stringResource(R.string.alert_text_vpn_profile_read_only), color = MaterialTheme.colorScheme.error)
			}
			FormSection(title = stringResource(R.string.profile_section_basic))
			{
				OutlinedTextField(
					value = state.gateway,
					onValueChange = { onChange(state.copy(gateway = it, gatewayError = null)) },
					label = { Text(stringResource(R.string.profile_gateway_label)) },
					supportingText = { Text(state.gatewayError ?: stringResource(R.string.profile_gateway_hint)) },
					isError = state.gatewayError != null,
					enabled = enabled,
					singleLine = true,
					shape = MaterialTheme.shapes.medium,
					modifier = Modifier.fillMaxWidth(),
				)
				ExposedDropdownMenuBox(expanded = typeExpanded, onExpandedChange = { if (enabled) typeExpanded = it }) {
					OutlinedTextField(
						value = types.getOrElse(state.vpnType.ordinal) { "" },
						onValueChange = {},
						readOnly = true,
						enabled = enabled,
						label = { Text(stringResource(R.string.profile_vpn_type_label)) },
						trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(typeExpanded) },
						modifier = Modifier.fillMaxWidth().menuAnchor(ExposedDropdownMenuAnchorType.PrimaryNotEditable),
					)
					ExposedDropdownMenu(expanded = typeExpanded, onDismissRequest = { typeExpanded = false }) {
						VpnType.values().forEachIndexed { index, type ->
							DropdownMenuItem(
								text = { Text(types.getOrElse(index) { type.identifier }) },
								onClick = {
									onChange(state.copy(vpnType = type))
									typeExpanded = false
								},
							)
						}
					}
				}
				if (state.vpnType.has(VpnTypeFeature.USER_PASS))
				{
					OutlinedTextField(
						value = state.username,
						onValueChange = { onChange(state.copy(username = it, usernameError = null)) },
						label = { Text(stringResource(R.string.profile_username_label)) },
						isError = state.usernameError != null,
						supportingText = state.usernameError?.let { { Text(it) } },
						enabled = enabled,
						singleLine = true,
						modifier = Modifier.fillMaxWidth(),
					)
					OutlinedTextField(
						value = state.password,
						onValueChange = { onChange(state.copy(password = it)) },
						label = { Text(stringResource(R.string.profile_password_label)) },
						supportingText = { Text(stringResource(R.string.profile_password_hint)) },
						enabled = enabled,
						singleLine = true,
						visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(),
						trailingIcon = {
							IconButton(onClick = { showPassword = !showPassword }) {
								Icon(if (showPassword) Icons.Default.VisibilityOff else Icons.Default.Visibility, null)
							}
						},
						keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
						modifier = Modifier.fillMaxWidth(),
					)
				}
				if (state.vpnType.has(VpnTypeFeature.CERTIFICATE))
				{
					TextButton(onClick = {
						KeyChain.choosePrivateKeyAlias(context as Activity, { alias ->
							onChange(latest.value.copy(userCertAlias = alias))
						}, arrayOf("RSA", "EC"), null, null, -1, state.userCertAlias)
					}, enabled = enabled) {
						Text(state.userCertAlias ?: stringResource(R.string.profile_user_select_certificate))
					}
				}
				Row(verticalAlignment = Alignment.CenterVertically) {
					Checkbox(
						checked = state.caAuto,
						onCheckedChange = { onChange(state.copy(caAuto = it)) },
						enabled = enabled,
					)
					Text(stringResource(R.string.profile_ca_auto_label), modifier = Modifier.clickable(enabled = enabled) {
						onChange(state.copy(caAuto = !state.caAuto))
					})
				}
				if (!state.caAuto)
				{
					TextButton(onClick = {
						val intent = Intent(context, TrustedCertificatesActivity::class.java)
						intent.action = TrustedCertificatesActivity.SELECT_CERTIFICATE
						pickCa.launch(intent)
					}, enabled = enabled) {
						Text(state.caLabel.ifEmpty { stringResource(R.string.profile_ca_select_certificate) })
					}
				}
				OutlinedTextField(
					value = state.name,
					onValueChange = { onChange(state.copy(name = it)) },
					label = { Text(stringResource(R.string.profile_name_label)) },
					supportingText = { Text(stringResource(R.string.profile_name_hint)) },
					enabled = enabled,
					singleLine = true,
					modifier = Modifier.fillMaxWidth(),
				)
				HorizontalDivider()
				val chevron by animateFloatAsState(if (state.advanced) 180f else 0f, label = "adv")
				ListItem(
					headlineContent = { Text(stringResource(R.string.profile_advanced_label)) },
					supportingContent = { Text(stringResource(R.string.profile_advanced_hint)) },
					trailingContent = {
						Icon(
							Icons.Default.ExpandMore,
							contentDescription = stringResource(R.string.profile_show_advanced_label),
							modifier = Modifier.rotate(chevron),
						)
					},
					colors = ListItemDefaults.colors(containerColor = Color.Transparent),
					modifier = Modifier
						.fillMaxWidth()
						.clickable { onChange(state.copy(advanced = !state.advanced)) },
				)
				AnimatedVisibility(
					visible = state.advanced,
					enter = expandVertically() + fadeIn(),
					exit = shrinkVertically() + fadeOut(),
				) {
					Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
					OutlinedTextField(state.remoteId, { onChange(state.copy(remoteId = it)) },
						label = { Text(stringResource(R.string.profile_remote_id_label)) },
						supportingText = { Text(stringResource(R.string.profile_remote_id_hint)) },
						enabled = enabled, singleLine = true, modifier = Modifier.fillMaxWidth())
					OutlinedTextField(state.localId, { onChange(state.copy(localId = it)) },
						label = { Text(stringResource(R.string.profile_local_id_label)) },
						supportingText = { Text(stringResource(R.string.profile_local_id_hint_user)) },
						enabled = enabled, singleLine = true, modifier = Modifier.fillMaxWidth())
					OutlinedTextField(state.dns, { onChange(state.copy(dns = it)) },
						label = { Text(stringResource(R.string.profile_dns_servers_label)) },
						supportingText = { Text(stringResource(R.string.profile_dns_servers_hint)) },
						enabled = enabled, singleLine = true, modifier = Modifier.fillMaxWidth())
					OutlinedTextField(state.mtu, { onChange(state.copy(mtu = it)) },
						label = { Text(stringResource(R.string.profile_mtu_label)) },
						enabled = enabled, singleLine = true, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
						modifier = Modifier.fillMaxWidth())
					OutlinedTextField(state.port, { onChange(state.copy(port = it)) },
						label = { Text(stringResource(R.string.profile_port_label)) },
						enabled = enabled, singleLine = true, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
						modifier = Modifier.fillMaxWidth())
					OutlinedTextField(state.natKeepalive, { onChange(state.copy(natKeepalive = it)) },
						label = { Text(stringResource(R.string.profile_nat_keepalive_label)) },
						enabled = enabled, singleLine = true, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
						modifier = Modifier.fillMaxWidth())
					SwitchRow(stringResource(R.string.profile_cert_req_label), state.certReq, enabled) { onChange(state.copy(certReq = it)) }
					SwitchRow(stringResource(R.string.profile_use_ocsp_label), state.useOcsp, enabled) { onChange(state.copy(useOcsp = it)) }
					SwitchRow(stringResource(R.string.profile_use_crl_label), state.useCrl, enabled) { onChange(state.copy(useCrl = it)) }
					SwitchRow(stringResource(R.string.profile_strict_revocation_label), state.strictRevocation, enabled) { onChange(state.copy(strictRevocation = it)) }
					SwitchRow(stringResource(R.string.profile_rsa_pss_label), state.rsaPss, enabled) { onChange(state.copy(rsaPss = it)) }
					SwitchRow(stringResource(R.string.profile_ipv6_transport_label), state.ipv6Transport, enabled) { onChange(state.copy(ipv6Transport = it)) }
					OutlinedTextField(state.includedSubnets, { onChange(state.copy(includedSubnets = it)) },
						label = { Text(stringResource(R.string.profile_included_subnets_label)) },
						enabled = enabled, modifier = Modifier.fillMaxWidth())
					OutlinedTextField(state.excludedSubnets, { onChange(state.copy(excludedSubnets = it)) },
						label = { Text(stringResource(R.string.profile_excluded_subnets_label)) },
						enabled = enabled, modifier = Modifier.fillMaxWidth())
					SwitchRow(
						label = stringResource(R.string.profile_split_tunnelingv4_title),
						checked = state.blockIpv4,
						enabled = enabled,
					) { onChange(state.copy(blockIpv4 = it)) }
					SwitchRow(
						label = stringResource(R.string.profile_split_tunnelingv6_title),
						supporting = stringResource(R.string.profile_split_tunnelingv6_hint),
						checked = state.blockIpv6,
						enabled = enabled,
					) { onChange(state.copy(blockIpv6 = it)) }
					ExposedDropdownMenuBox(expanded = appsExpanded, onExpandedChange = { if (enabled) appsExpanded = it }) {
						OutlinedTextField(
							value = appsHandling.getOrElse(state.appsHandling.ordinal) { "" },
							onValueChange = {},
							readOnly = true,
							enabled = enabled,
							label = { Text(stringResource(R.string.profile_select_apps)) },
							trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(appsExpanded) },
							modifier = Modifier.fillMaxWidth().menuAnchor(ExposedDropdownMenuAnchorType.PrimaryNotEditable),
						)
						ExposedDropdownMenu(expanded = appsExpanded, onDismissRequest = { appsExpanded = false }) {
							SelectedAppsHandling.values().forEachIndexed { index, handling ->
								DropdownMenuItem(
									text = { Text(appsHandling.getOrElse(index) { handling.name }) },
									onClick = {
										onChange(state.copy(appsHandling = handling))
										appsExpanded = false
									},
								)
							}
						}
					}
					if (state.appsHandling != SelectedAppsHandling.SELECTED_APPS_DISABLE)
					{
						TextButton(onClick = {
							val intent = Intent(context, SelectedApplicationsActivity::class.java)
							intent.putStringArrayListExtra(VpnProfileDataSource.KEY_SELECTED_APPS_LIST, ArrayList(state.selectedApps))
							pickApps.launch(intent)
						}, enabled = enabled) {
							Text(stringResource(R.string.profile_select_apps) + " (${state.selectedApps.size})")
						}
					}
					OutlinedTextField(state.ikeProposal, { onChange(state.copy(ikeProposal = it)) },
						label = { Text(stringResource(R.string.profile_proposals_ike_label)) },
						enabled = enabled, modifier = Modifier.fillMaxWidth())
					OutlinedTextField(state.espProposal, { onChange(state.copy(espProposal = it)) },
						label = { Text(stringResource(R.string.profile_proposals_esp_label)) },
						enabled = enabled, modifier = Modifier.fillMaxWidth())
					OutlinedTextField(state.proxyHost, { onChange(state.copy(proxyHost = it)) },
						label = { Text(stringResource(R.string.profile_proxy_host_label)) },
						enabled = enabled, modifier = Modifier.fillMaxWidth())
					OutlinedTextField(state.proxyPort, { onChange(state.copy(proxyPort = it)) },
						label = { Text(stringResource(R.string.profile_proxy_port_label)) },
						enabled = enabled, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
						modifier = Modifier.fillMaxWidth())
					OutlinedTextField(state.proxyExclusions, { onChange(state.copy(proxyExclusions = it)) },
						label = { Text(stringResource(R.string.profile_proxy_exclusions_label)) },
						enabled = enabled, modifier = Modifier.fillMaxWidth())
					}
				}
			}
		}
	}
}

@Composable
private fun FormSection(title: String, content: @Composable () -> Unit)
{
	Surface(
		shape = MaterialTheme.shapes.large,
		color = MaterialTheme.colorScheme.surfaceContainerLow,
		modifier = Modifier.fillMaxWidth(),
	) {
		Column(Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(12.dp))
		{
			Text(
				text = title.uppercase(),
				style = MaterialTheme.typography.labelMedium,
				color = MaterialTheme.colorScheme.onSurfaceVariant,
			)
			content()
		}
	}
}

@Composable
private fun SwitchRow(
	label: String,
	checked: Boolean,
	enabled: Boolean,
	supporting: String? = null,
	onChange: (Boolean) -> Unit,
)
{
	ListItem(
		headlineContent = { Text(label) },
		supportingContent = supporting?.let { { Text(it) } },
		trailingContent = {
			Switch(checked = checked, onCheckedChange = onChange, enabled = enabled)
		},
		colors = ListItemDefaults.colors(containerColor = Color.Transparent),
		modifier = Modifier.fillMaxWidth(),
	)
}
