/*
 * Copyright (c) 2025 Element Creations Ltd.
 * Copyright 2025 New Vector Ltd.
 *
 * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
 * Please see LICENSE files in the repository root for full details.
 */

package io.element.android.features.securityandprivacy.impl.root

import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.progressSemantics
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ListItemDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.appconfig.LearnMoreConfig
import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.securityandprivacy.impl.R
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.coverage.ExcludeFromCoverage
import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
import io.element.android.libraries.designsystem.components.dialogs.SaveChangesDialog
import io.element.android.libraries.designsystem.components.list.ListItemContent
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.preview.PreviewWithLargeHeight
import io.element.android.libraries.designsystem.text.stringWithLink
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.IconSource
import io.element.android.libraries.designsystem.theme.components.ListItem
import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.collections.immutable.ImmutableList

@Composable
fun SecurityAndPrivacyView(
    state: SecurityAndPrivacyState,
    onLinkClick: (String) -> Unit,
    modifier: Modifier = Modifier,
) {
    BackHandler {
        state.eventSink(SecurityAndPrivacyEvent.Exit)
    }
    Scaffold(
        modifier = modifier,
        topBar = {
            SecurityAndPrivacyToolbar(
                isSaveActionEnabled = state.canBeSaved,
                onBackClick = {
                    state.eventSink(SecurityAndPrivacyEvent.Exit)
                },
                onSaveClick = {
                    state.eventSink(SecurityAndPrivacyEvent.Save)
                },
            )
        }
    ) { padding ->
        Column(
            modifier = Modifier
                .padding(padding)
                .imePadding()
                .verticalScroll(rememberScrollState())
                .consumeWindowInsets(padding),
            verticalArrangement = Arrangement.spacedBy(32.dp),
        ) {
            if (state.showRoomAccessSection) {
                RoomAccessSection(
                    state = state,
                    modifier = Modifier.padding(top = 24.dp),
                )
            }
            if (state.showRoomVisibilitySections) {
                RoomVisibilitySection(state.homeserverName)
                RoomAddressSection(
                    roomAddress = state.editedSettings.address,
                    homeserverName = state.homeserverName,
                    onRoomAddressClick = { state.eventSink(SecurityAndPrivacyEvent.EditRoomAddress) },
                    isVisibleInRoomDirectory = state.editedSettings.isVisibleInRoomDirectory,
                    onVisibilityChange = {
                        state.eventSink(SecurityAndPrivacyEvent.ToggleRoomVisibility)
                    },
                )
            }
            if (state.showEncryptionSection) {
                EncryptionSection(
                    isRoomEncrypted = state.editedSettings.isEncrypted,
                    // encryption can't be disabled once enabled
                    canToggleEncryption = !state.savedSettings.isEncrypted,
                    onToggleEncryption = { state.eventSink(SecurityAndPrivacyEvent.ToggleEncryptionState) },
                    showConfirmation = state.showEnableEncryptionConfirmation,
                    onDismissConfirmation = { state.eventSink(SecurityAndPrivacyEvent.CancelEnableEncryption) },
                    onConfirmEncryption = { state.eventSink(SecurityAndPrivacyEvent.ConfirmEnableEncryption) },
                )
            }
            if (state.showHistoryVisibilitySection) {
                HistoryVisibilitySection(
                    editedOption = state.editedSettings.historyVisibility,
                    savedOptions = state.savedSettings.historyVisibility,
                    availableOptions = state.availableHistoryVisibilities,
                    onSelectOption = { state.eventSink(SecurityAndPrivacyEvent.ChangeHistoryVisibility(it)) },
                    onLinkClick = onLinkClick,
                )
            }
        }
    }
    AsyncActionView(
        async = state.saveAction,
        onSuccess = { },
        onErrorDismiss = { state.eventSink(SecurityAndPrivacyEvent.DismissSaveError) },
        confirmationDialog = { confirming ->
            when (confirming) {
                is AsyncAction.ConfirmingCancellation ->
                    SaveChangesDialog(
                        onSaveClick = { state.eventSink(SecurityAndPrivacyEvent.Save) },
                        onDiscardClick = { state.eventSink(SecurityAndPrivacyEvent.Exit) },
                        onDismiss = { state.eventSink(SecurityAndPrivacyEvent.DismissExitConfirmation) }
                    )
            }
        },
        errorMessage = { stringResource(CommonStrings.error_unknown) },
        progressDialog = {
            AsyncActionViewDefaults.ProgressDialog(
                progressText = stringResource(CommonStrings.common_saving),
            )
        },
        onRetry = { state.eventSink(SecurityAndPrivacyEvent.Save) },
    )
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun SecurityAndPrivacyToolbar(
    isSaveActionEnabled: Boolean,
    onBackClick: () -> Unit,
    onSaveClick: () -> Unit,
    modifier: Modifier = Modifier,
) {
    TopAppBar(
        modifier = modifier,
        titleStr = stringResource(R.string.screen_security_and_privacy_title),
        navigationIcon = { BackButton(onClick = onBackClick) },
        actions = {
            TextButton(
                text = stringResource(CommonStrings.action_save),
                enabled = isSaveActionEnabled,
                onClick = onSaveClick,
            )
        }
    )
}

@Composable
private fun SecurityAndPrivacySection(
    title: String,
    modifier: Modifier = Modifier,
    subtitle: AnnotatedString? = null,
    content: @Composable ColumnScope.() -> Unit,
) {
    Column(
        modifier = modifier.selectableGroup()
    ) {
        Text(
            text = title,
            style = ElementTheme.typography.fontBodyLgMedium,
            color = ElementTheme.colors.textPrimary,
            modifier = Modifier.padding(horizontal = 16.dp),
        )
        if (subtitle != null) {
            Spacer(Modifier.height(8.dp))
            Text(
                text = subtitle,
                style = ElementTheme.typography.fontBodyMdRegular,
                color = ElementTheme.colors.textSecondary,
                modifier = Modifier.padding(horizontal = 16.dp),
            )
        }
        content()
    }
}

@Composable
private fun RoomAccessSection(
    state: SecurityAndPrivacyState,
    modifier: Modifier = Modifier,
) {
    val edited = state.editedSettings.roomAccess

    fun onSelectOption(option: SecurityAndPrivacyRoomAccess) {
        state.eventSink(SecurityAndPrivacyEvent.ChangeRoomAccess(option))
    }

    fun onSpaceMemberAccessClick() {
        state.eventSink(SecurityAndPrivacyEvent.SelectSpaceMemberAccess)
    }

    fun onAskToJoinWithSpaceMembersClick() {
        state.eventSink(SecurityAndPrivacyEvent.SelectAskToJoinWithSpaceMembersAccess)
    }

    fun onManageSpacesClick() {
        state.eventSink(SecurityAndPrivacyEvent.ManageAuthorizedSpaces)
    }

    SecurityAndPrivacySection(
        title = stringResource(R.string.screen_security_and_privacy_room_access_section_header),
        modifier = modifier,
    ) {
        ListItem(
            headlineContent = { Text(text = stringResource(R.string.screen_security_and_privacy_room_access_anyone_option_title)) },
            supportingContent = { Text(text = stringResource(R.string.screen_security_and_privacy_room_access_anyone_option_description)) },
            trailingContent = ListItemContent.RadioButton(selected = edited == SecurityAndPrivacyRoomAccess.Anyone),
            leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Public())),
            onClick = { onSelectOption(SecurityAndPrivacyRoomAccess.Anyone) },
        )
        if (state.showSpaceMemberOption) {
            ListItem(
                headlineContent = { Text(text = stringResource(R.string.screen_security_and_privacy_room_access_space_members_option_title)) },
                supportingContent = {
                    Text(text = state.spaceMemberDescription())
                },
                trailingContent = ListItemContent.RadioButton(selected = state.editedSettings.roomAccess is SecurityAndPrivacyRoomAccess.SpaceMember),
                leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Space())),
                onClick = ::onSpaceMemberAccessClick,
                enabled = state.isSpaceMemberSelectable,
            )
        }
        if (state.showAskToJoinOption) {
            ListItem(
                headlineContent = { Text(text = stringResource(R.string.screen_security_and_privacy_ask_to_join_option_title)) },
                supportingContent = { Text(text = stringResource(R.string.screen_security_and_privacy_ask_to_join_option_description)) },
                trailingContent = ListItemContent.RadioButton(selected = edited == SecurityAndPrivacyRoomAccess.AskToJoin),
                onClick = { onSelectOption(SecurityAndPrivacyRoomAccess.AskToJoin) },
                leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.UserAdd())),
                enabled = state.isAskToJoinSelectable,
            )
        }
        if (state.showAskToJoinWithSpaceMemberOption) {
            ListItem(
                headlineContent = { Text(text = stringResource(R.string.screen_security_and_privacy_ask_to_join_option_title)) },
                supportingContent = { Text(text = state.askToJoinWithSpaceMembersDescription()) },
                trailingContent = ListItemContent.RadioButton(selected = edited is SecurityAndPrivacyRoomAccess.AskToJoinWithSpaceMember),
                onClick = ::onAskToJoinWithSpaceMembersClick,
                leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.UserAdd())),
                enabled = state.isAskToJoinWithSpaceMembersSelectable,
            )
        }
        ListItem(
            headlineContent = { Text(text = stringResource(R.string.screen_security_and_privacy_room_access_invite_only_option_title)) },
            supportingContent = { Text(text = stringResource(R.string.screen_security_and_privacy_room_access_invite_only_option_description)) },
            trailingContent = ListItemContent.RadioButton(selected = edited == SecurityAndPrivacyRoomAccess.InviteOnly),
            leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Lock())),
            onClick = { onSelectOption(SecurityAndPrivacyRoomAccess.InviteOnly) },
        )
        if (state.showManageSpaceFooter) {
            val footerText = stringWithLink(
                textRes = R.string.screen_security_and_privacy_room_access_footer,
                url = "",
                linkTextRes = R.string.screen_security_and_privacy_room_access_footer_manage_spaces_action,
                onLinkClick = { onManageSpacesClick() },
            )
            Text(
                text = footerText,
                style = ElementTheme.typography.fontBodySmRegular,
                color = ElementTheme.colors.textSecondary,
                modifier = Modifier.padding(bottom = 12.dp, start = 56.dp, end = 24.dp)
            )
        }
    }
}

@Composable
private fun RoomVisibilitySection(
    homeserverName: String,
    modifier: Modifier = Modifier,
) {
    SecurityAndPrivacySection(
        title = stringResource(R.string.screen_security_and_privacy_room_visibility_section_header),
        modifier = modifier,
    ) {
        Spacer(Modifier.height(12.dp))
        Text(
            text = stringResource(R.string.screen_security_and_privacy_room_visibility_section_footer, homeserverName),
            style = ElementTheme.typography.fontBodyMdRegular,
            color = ElementTheme.colors.textSecondary,
            modifier = Modifier.padding(horizontal = 16.dp),
        )
    }
}

@Composable
private fun RoomAddressSection(
    roomAddress: String?,
    homeserverName: String,
    isVisibleInRoomDirectory: AsyncData<Boolean>,
    onRoomAddressClick: () -> Unit,
    onVisibilityChange: () -> Unit,
    modifier: Modifier = Modifier,
) {
    SecurityAndPrivacySection(
        title = stringResource(R.string.screen_security_and_privacy_room_address_section_header),
        modifier = modifier,
    ) {
        ListItem(
            headlineContent = {
                Text(text = roomAddress ?: stringResource(R.string.screen_security_and_privacy_add_room_address_action))
            },
            trailingContent = if (roomAddress.isNullOrEmpty()) ListItemContent.Icon(IconSource.Vector(CompoundIcons.Plus())) else null,
            supportingContent = { Text(text = stringResource(R.string.screen_security_and_privacy_room_address_section_footer)) },
            onClick = onRoomAddressClick,
            colors = ListItemDefaults.colors(trailingIconColor = ElementTheme.colors.iconAccentPrimary),
        )

        ListItem(
            headlineContent = { Text(text = stringResource(R.string.screen_security_and_privacy_room_directory_visibility_toggle_title)) },
            supportingContent = {
                Text(text = stringResource(R.string.screen_security_and_privacy_room_directory_visibility_toggle_description, homeserverName))
            },
            onClick = if (isVisibleInRoomDirectory.isSuccess()) onVisibilityChange else null,
            trailingContent = when (isVisibleInRoomDirectory) {
                is AsyncData.Uninitialized, is AsyncData.Loading -> {
                    ListItemContent.Custom {
                        CircularProgressIndicator(
                            modifier = Modifier
                                .progressSemantics()
                                .size(20.dp),
                            strokeWidth = 2.dp
                        )
                    }
                }
                is AsyncData.Failure -> {
                    ListItemContent.Switch(
                        checked = false,
                        enabled = false,
                    )
                }
                is AsyncData.Success -> {
                    ListItemContent.Switch(
                        checked = isVisibleInRoomDirectory.data,
                    )
                }
            }
        )
    }
}

@Composable
private fun EncryptionSection(
    isRoomEncrypted: Boolean,
    canToggleEncryption: Boolean,
    showConfirmation: Boolean,
    onToggleEncryption: () -> Unit,
    onConfirmEncryption: () -> Unit,
    onDismissConfirmation: () -> Unit,
    modifier: Modifier = Modifier,
) {
    SecurityAndPrivacySection(
        title = stringResource(R.string.screen_security_and_privacy_encryption_section_header),
        modifier = modifier,
    ) {
        ListItem(
            headlineContent = { Text(text = stringResource(R.string.screen_security_and_privacy_encryption_toggle_title)) },
            supportingContent = { Text(text = stringResource(R.string.screen_security_and_privacy_encryption_section_footer)) },
            trailingContent = ListItemContent.Switch(
                checked = isRoomEncrypted,
                enabled = canToggleEncryption,
            ),
            onClick = if (canToggleEncryption) onToggleEncryption else null
        )
    }
    if (showConfirmation) {
        ConfirmationDialog(
            title = stringResource(R.string.screen_security_and_privacy_enable_encryption_alert_title),
            content = stringResource(R.string.screen_security_and_privacy_enable_encryption_alert_description),
            submitText = stringResource(R.string.screen_security_and_privacy_enable_encryption_alert_confirm_button_title),
            onSubmitClick = onConfirmEncryption,
            onDismiss = onDismissConfirmation,
        )
    }
}

@Composable
private fun HistoryVisibilitySection(
    editedOption: SecurityAndPrivacyHistoryVisibility?,
    savedOptions: SecurityAndPrivacyHistoryVisibility?,
    availableOptions: ImmutableList<SecurityAndPrivacyHistoryVisibility>,
    onSelectOption: (SecurityAndPrivacyHistoryVisibility) -> Unit,
    onLinkClick: (String) -> Unit,
    modifier: Modifier = Modifier,
) {
    SecurityAndPrivacySection(
        title = stringResource(R.string.screen_security_and_privacy_room_history_section_header),
        subtitle = stringWithLink(
            textRes = R.string.screen_security_and_privacy_room_history_section_footer,
            url = LearnMoreConfig.HISTORY_VISIBLE_URL,
            onLinkClick = onLinkClick,
        ),
        modifier = modifier,
    ) {
        for (availableOption in availableOptions) {
            val isSelected = availableOption == editedOption
            HistoryVisibilityItem(
                option = availableOption,
                isSelected = isSelected,
                onSelectOption = onSelectOption,
            )
        }
        // Also show the saved option if it's not in the available options, but disabled
        if (savedOptions != null && !availableOptions.contains(savedOptions)) {
            HistoryVisibilityItem(
                option = savedOptions,
                isSelected = true,
                isEnabled = false,
                onSelectOption = {},
            )
        }
    }
}

@Composable
private fun HistoryVisibilityItem(
    option: SecurityAndPrivacyHistoryVisibility,
    isSelected: Boolean,
    onSelectOption: (SecurityAndPrivacyHistoryVisibility) -> Unit,
    modifier: Modifier = Modifier,
    isEnabled: Boolean = true,
) {
    val headlineText = when (option) {
        SecurityAndPrivacyHistoryVisibility.Invited -> stringResource(R.string.screen_security_and_privacy_room_history_since_invite_option_title)
        SecurityAndPrivacyHistoryVisibility.Shared -> stringResource(R.string.screen_security_and_privacy_room_history_since_selecting_option_title)
        SecurityAndPrivacyHistoryVisibility.WorldReadable -> stringResource(R.string.screen_security_and_privacy_room_history_anyone_option_title)
    }
    ListItem(
        headlineContent = { Text(text = headlineText) },
        trailingContent = ListItemContent.RadioButton(selected = isSelected, enabled = isEnabled),
        onClick = { onSelectOption(option) },
        enabled = isEnabled,
        modifier = modifier,
    )
}

@PreviewWithLargeHeight
@Composable
internal fun SecurityAndPrivacyViewLightPreview(@PreviewParameter(SecurityAndPrivacyStateProvider::class) state: SecurityAndPrivacyState) =
    ElementPreviewLight { ContentToPreview(state) }

@PreviewWithLargeHeight
@Composable
internal fun SecurityAndPrivacyViewDarkPreview(@PreviewParameter(SecurityAndPrivacyStateProvider::class) state: SecurityAndPrivacyState) =
    ElementPreviewDark { ContentToPreview(state) }

@ExcludeFromCoverage
@Composable
private fun ContentToPreview(state: SecurityAndPrivacyState) {
    SecurityAndPrivacyView(
        state = state,
        onLinkClick = {},
    )
}
