package com.github.nullptroma.wallenc.ui.elements

import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Lock
import androidx.compose.material.icons.filled.LockOpen
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.ripple
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
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.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.PlatformTextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.github.nullptroma.wallenc.domain.datatypes.StorageMetaLoadState
import com.github.nullptroma.wallenc.domain.datatypes.Tree
import com.github.nullptroma.wallenc.domain.interfaces.IStorageInfo
import com.github.nullptroma.wallenc.ui.R
import com.github.nullptroma.wallenc.ui.utils.debouncedLambda
import java.util.UUID

@Composable
fun StorageTree(
    modifier: Modifier,
    tree: Tree<IStorageInfo>,
    isUuidBusy: (UUID) -> Boolean,
    onClick: (Tree<IStorageInfo>) -> Unit,
    onRename: (Tree<IStorageInfo>, String) -> Unit,
    onRemove: (Tree<IStorageInfo>) -> Unit,
    onEncrypt: (Tree<IStorageInfo>, String, Boolean, Boolean) -> Unit,
    onOpenEncrypted: (Tree<IStorageInfo>, String, Boolean) -> Unit,
    onCloseEncrypted: (Tree<IStorageInfo>) -> Unit,
    onDisableEncryption: (Tree<IStorageInfo>) -> Unit,
    getStatusTextRes: (Tree<IStorageInfo>) -> Int,
    isEncryptionOpened: (Tree<IStorageInfo>) -> Boolean,
    isStorageSyncLockHeld: suspend (IStorageInfo) -> Boolean,
    onClearStorageSyncLock: (IStorageInfo) -> Unit,
) {
    val cur = tree.value
    val rowBusy = isUuidBusy(cur.uuid)
    val numOfFiles by cur.numberOfFiles.collectAsStateWithLifecycle()
    val size by cur.size.collectAsStateWithLifecycle()
    val metaInfo by cur.metaInfo.collectAsStateWithLifecycle()
    val metaLoadState by cur.metaLoadState.collectAsStateWithLifecycle()
    val isAvailable by cur.isAvailable.collectAsStateWithLifecycle()
    val metaUnavailable = metaLoadState == StorageMetaLoadState.Unavailable
    val rowEnabled = isAvailable && !rowBusy && !metaUnavailable
    val isEncrypted = metaInfo.encInfo != null
    val isOpened = isEncryptionOpened(tree)
    val borderColor =
        if (cur.isVirtualStorage) MaterialTheme.colorScheme.secondary else MaterialTheme.colorScheme.primary
    val yesWord = stringResource(R.string.storage_value_yes)
    val noWord = stringResource(R.string.storage_value_no)
    val unavailableHint = stringResource(R.string.storage_unavailable_hint)
    val metaUnavailableHint = stringResource(R.string.storage_meta_unavailable_hint)
    Column(modifier) {
        Box(
            modifier = Modifier
                .fillMaxWidth()
                .wrapContentHeight()
                .zIndex(100f),
        ) {
            val interactionSource = remember { MutableInteractionSource() }
            Box(
                modifier = Modifier
                    .matchParentSize()
                    .padding(end = 16.dp)
                    .clip(CardDefaults.shape)
                    .background(borderColor)
                    .clickable(
                        interactionSource = interactionSource,
                        indication = ripple(),
                        enabled = false,
                        onClick = { },
                    ),
            )
            Card(
                interactionSource = interactionSource,
                modifier = Modifier
                    .padding(start = 8.dp)
                    .fillMaxWidth()
                    .wrapContentHeight(),
                elevation = CardDefaults.cardElevation(
                    defaultElevation = 4.dp,
                ),
                enabled = rowEnabled,
                onClick = debouncedLambda(debounceMs = 500) {
                    if (rowEnabled) {
                        onClick(tree)
                    }
                },
            ) {
                Row(
                    modifier = Modifier
                        .fillMaxWidth()
                        .wrapContentHeight(),
                ) {
                    Column(
                        modifier = Modifier
                            .weight(1f)
                            .padding(8.dp),
                    ) {
                        Text(metaInfo.name ?: stringResource(R.string.no_name))
                        Text(
                            text = stringResource(
                                R.string.storage_field_available,
                                if (isAvailable) yesWord else noWord,
                            ),
                            style = MaterialTheme.typography.bodySmall,
                        )
                        Text(
                            text = stringResource(
                                R.string.storage_field_files,
                                numOfFiles?.toString() ?: "—",
                            ),
                            style = MaterialTheme.typography.bodySmall,
                        )
                        Text(
                            text = stringResource(
                                R.string.storage_field_size,
                                size?.toString() ?: "—",
                            ),
                            style = MaterialTheme.typography.bodySmall,
                        )
                        Text(
                            text = stringResource(
                                R.string.storage_field_virtual,
                                if (cur.isVirtualStorage) yesWord else noWord,
                            ),
                            style = MaterialTheme.typography.bodySmall,
                        )
                        if (metaUnavailable) {
                            Text(
                                text = metaUnavailableHint,
                                style = MaterialTheme.typography.bodySmall,
                                color = MaterialTheme.colorScheme.error,
                            )
                        } else if (!isAvailable) {
                            Text(
                                text = unavailableHint,
                                style = MaterialTheme.typography.bodySmall,
                                color = MaterialTheme.colorScheme.error,
                            )
                        }
                    }
                    Column(
                        modifier = Modifier
                            .widthIn(min = 112.dp)
                            .padding(end = 4.dp),
                        horizontalAlignment = Alignment.End,
                    ) {
                        var expanded by remember { mutableStateOf(false) }
                        var syncLockHeld by remember { mutableStateOf<Boolean?>(null) }
                        LaunchedEffect(expanded, cur.uuid) {
                            if (expanded) {
                                syncLockHeld = null
                                syncLockHeld = isStorageSyncLockHeld(cur)
                            } else {
                                syncLockHeld = null
                            }
                        }
                        var showRenameDialog by remember { mutableStateOf(false) }
                        var showRemoveConfirmDialog by remember { mutableStateOf(false) }
                        var showLockDialog by remember { mutableStateOf(false) }
                        var showSetupEncryptionDialog by remember { mutableStateOf(false) }
                        var showOpenEncryptionDialog by remember { mutableStateOf(false) }
                        Box(modifier = Modifier.padding(0.dp, 0.dp, 0.dp, 0.dp)) {
                            Row(
                                verticalAlignment = Alignment.CenterVertically,
                            ) {
                                if (rowBusy) {
                                    CircularProgressIndicator(
                                        modifier = Modifier
                                            .padding(end = 4.dp)
                                            .size(22.dp),
                                        strokeWidth = 2.dp,
                                    )
                                }
                                IconButton(
                                    onClick = { expanded = !expanded },
                                    enabled = rowEnabled,
                                ) {
                                    Icon(
                                        Icons.Default.MoreVert,
                                        contentDescription = stringResource(
                                            if (rowBusy) {
                                                R.string.storage_row_task_running_cd
                                            } else {
                                                R.string.show_storage_item_menu
                                            },
                                        ),
                                    )
                                }
                            }
                            DropdownMenu(
                                expanded = expanded,
                                onDismissRequest = { expanded = false },
                            ) {
                                DropdownMenuItem(
                                    enabled = rowEnabled,
                                    onClick = {
                                        expanded = false
                                        if (rowEnabled) showRenameDialog = true
                                    },
                                    text = {
                                        Text(
                                            when {
                                                !isAvailable -> stringResource(
                                                    R.string.storage_menu_unavailable,
                                                    stringResource(R.string.rename),
                                                )
                                                rowBusy -> stringResource(R.string.storage_menu_busy, stringResource(R.string.rename))
                                                else -> stringResource(R.string.rename)
                                            },
                                        )
                                    },
                                )
                                HorizontalDivider()
                                DropdownMenuItem(
                                    enabled = rowEnabled,
                                    onClick = {
                                        expanded = false
                                        if (rowEnabled) showRemoveConfirmDialog = true
                                    },
                                    text = {
                                        Text(
                                            when {
                                                !isAvailable -> stringResource(
                                                    R.string.storage_menu_unavailable,
                                                    stringResource(R.string.remove),
                                                )
                                                rowBusy -> stringResource(R.string.storage_menu_busy, stringResource(R.string.remove))
                                                else -> stringResource(R.string.remove)
                                            },
                                        )
                                    },
                                )
                                if (!isEncrypted) {
                                    HorizontalDivider()
                                    DropdownMenuItem(
                                        enabled = rowEnabled,
                                        onClick = {
                                            expanded = false
                                            if (rowEnabled) showSetupEncryptionDialog = true
                                        },
                                        text = {
                                            Text(
                                                when {
                                                    !isAvailable -> stringResource(
                                                        R.string.storage_menu_unavailable,
                                                        stringResource(R.string.encrypt),
                                                    )
                                                    rowBusy -> stringResource(R.string.storage_menu_busy, stringResource(R.string.encrypt))
                                                    else -> stringResource(R.string.encrypt)
                                                },
                                            )
                                        },
                                    )
                                }
                                HorizontalDivider()
                                DropdownMenuItem(
                                    enabled = syncLockHeld == true && !rowBusy,
                                    onClick = {
                                        expanded = false
                                        if (syncLockHeld == true && !rowBusy) {
                                            onClearStorageSyncLock(cur)
                                        }
                                    },
                                    text = {
                                        Text(
                                            when (syncLockHeld) {
                                                null -> stringResource(R.string.storage_sync_lock_checking)
                                                true -> stringResource(R.string.storage_sync_unlock_action)
                                                false -> stringResource(R.string.storage_sync_not_locked)
                                            },
                                        )
                                    },
                                )
                            }

                            if (showRenameDialog) {
                                TextEditCancelOkDialog(
                                    onDismiss = { showRenameDialog = false },
                                    onConfirmation = { newName ->
                                        showRenameDialog = false
                                        onRename(tree, newName)
                                    },
                                    title = stringResource(R.string.new_name_title),
                                    startString = metaInfo.name ?: "",
                                )
                            }

                            if (showRemoveConfirmDialog) {
                                ConfirmationCancelOkDialog(
                                    onDismiss = { showRemoveConfirmDialog = false },
                                    title = stringResource(
                                        R.string.remove_confirmation_dialog,
                                        metaInfo.name ?: stringResource(R.string.no_name),
                                    ),
                                    onConfirmation = {
                                        showRemoveConfirmDialog = false
                                        onRemove(tree)
                                    },
                                )
                            }

                            if (showLockDialog) {
                                StorageEncryptionActionsDialog(
                                    onDismiss = { showLockDialog = false },
                                    title = metaInfo.name ?: stringResource(R.string.no_name),
                                    isOpened = isOpened,
                                    onOpen = {
                                        showLockDialog = false
                                        showOpenEncryptionDialog = true
                                    },
                                    onClose = {
                                        showLockDialog = false
                                        onCloseEncrypted(tree)
                                    },
                                    onDisable = {
                                        showLockDialog = false
                                        onDisableEncryption(tree)
                                    },
                                )
                            }

                            if (showSetupEncryptionDialog) {
                                EncryptionSetupDialog(
                                    onDismiss = { showSetupEncryptionDialog = false },
                                    onConfirmation = { password, encryptPath, rememberPassword ->
                                        showSetupEncryptionDialog = false
                                        onEncrypt(tree, password, encryptPath, rememberPassword)
                                    },
                                )
                            }

                            if (showOpenEncryptionDialog) {
                                OpenEncryptedStorageDialog(
                                    onDismiss = { showOpenEncryptionDialog = false },
                                    onConfirmation = { password, rememberPassword ->
                                        showOpenEncryptionDialog = false
                                        onOpenEncrypted(tree, password, rememberPassword)
                                    },
                                )
                            }
                        }
                        if (isEncrypted) {
                            IconButton(
                                onClick = { showLockDialog = true },
                                enabled = rowEnabled,
                            ) {
                                Icon(
                                    if (isOpened) Icons.Default.LockOpen else Icons.Default.Lock,
                                    contentDescription = stringResource(R.string.storage_lock_actions),
                                )
                            }
                        }
                        Text(
                            modifier = Modifier
                                .padding(top = 4.dp, end = 8.dp),
                            text = stringResource(getStatusTextRes(tree)),
                            textAlign = TextAlign.End,
                            fontSize = 11.sp,
                        )
                        Text(
                            modifier = Modifier
                                .padding(end = 8.dp, bottom = 8.dp),
                            text = cur.uuid.toString(),
                            textAlign = TextAlign.End,
                            fontSize = 8.sp,
                            style = LocalTextStyle.current.copy(
                                platformStyle = PlatformTextStyle(
                                    includeFontPadding = true,
                                ),
                            ),
                        )
                    }
                }
            }
        }
        for (i in tree.children ?: listOf()) {
            StorageTree(
                Modifier
                    .padding(16.dp, 0.dp, 0.dp, 0.dp)
                    .offset(y = (-4).dp),
                tree = i,
                isUuidBusy = isUuidBusy,
                onClick = onClick,
                onRename,
                onRemove,
                onEncrypt,
                onOpenEncrypted,
                onCloseEncrypted,
                onDisableEncryption,
                getStatusTextRes,
                isEncryptionOpened,
                isStorageSyncLockHeld,
                onClearStorageSyncLock,
            )
        }
    }
}
