package com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory

import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.calculateStartPadding
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.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.AddCircle
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.pixelized.desktop.lwa.LocalBlurController
import com.pixelized.desktop.lwa.ui.composable.character.inventory.InventoryDialog
import com.pixelized.desktop.lwa.ui.composable.character.inventory.InventoryDialogViewModel
import com.pixelized.desktop.lwa.ui.composable.character.item.ItemDetailDialog
import com.pixelized.desktop.lwa.ui.composable.character.item.ItemDetailDialogViewModel
import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialog
import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialogViewModel
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackHandler
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextField
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.item.InventoryItem
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.item.InventoryItemUio
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.item.InventoryPurse
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.item.PurseUio
import com.pixelized.desktop.lwa.ui.theme.color.component.LwaButtonColors
import com.pixelized.desktop.lwa.ui.theme.color.component.LwaTextFieldColors
import com.pixelized.desktop.lwa.ui.theme.lwa
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.character__inventory__add_to_inventory__action
import lwacharactersheet.composeapp.generated.resources.ic_cancel_24dp
import lwacharactersheet.composeapp.generated.resources.ic_filter_list_24dp
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource
import org.koin.compose.viewmodel.koinViewModel

@Stable
data class CharacterDetailInventoryUio(
    val characterSheetId: String,
    val addItemAction: StateFlow<Boolean>,
    val showFilter: StateFlow<Boolean>,
    val filter: LwaTextFieldUio,
    val purse: PurseUio,
    val items: List<InventoryItemUio>,
)

@Stable
object CharacterDetailInventoryDefault {
    @Stable
    val padding = PaddingValues(
        start = 16.dp,
        end = 16.dp,
        top = 8.dp,
        bottom = 8.dp,
    )

    @Stable
    val spacing: Dp = 8.dp
}

@Composable
fun CharacterDetailInventory(
    modifier: Modifier = Modifier,
    paddings: PaddingValues = CharacterDetailInventoryDefault.padding,
    spacing: Dp = CharacterDetailInventoryDefault.spacing,
    purseViewModel: PurseDialogViewModel = koinViewModel(),
    inventoryDialogViewModel: InventoryDialogViewModel = koinViewModel(),
    itemDetailDialogViewModel: ItemDetailDialogViewModel = koinViewModel(),
    inventory: State<CharacterDetailInventoryUio?>,
) {
    val focus = LocalFocusManager.current
    val scope = rememberCoroutineScope()

    when (val unWrap = inventory.value) {
        null -> Box(modifier = modifier)

        else -> CharacterDetailInventoryContent(
            modifier = modifier,
            paddings = paddings,
            spacing = spacing,
            inventory = unWrap,
            onPurse = {
                purseViewModel.showPurseDialog(
                    characterSheetId = it,
                )
                focus.clearFocus(force = true)
            },
            onItem = { item ->
                itemDetailDialogViewModel.showItemDialog(
                    characterSheetId = item.characterSheetId,
                    inventoryId = item.inventoryId,
                    itemId = item.itemId,
                )
                focus.clearFocus(force = true)
            },
            onAddItem = {
                inventoryDialogViewModel.showInventoryDialog(
                    characterSheetId = it,
                )
                focus.clearFocus(force = true)
            },
            onConsume = {
                scope.launch {
                    itemDetailDialogViewModel.consumeInventoryItem(
                        characterSheetId = it.characterSheetId,
                        inventoryId = it.inventoryId,
                    )
                }
                focus.clearFocus(force = true)
            },
            onEquip = {
                scope.launch {
                    itemDetailDialogViewModel.equipInventoryItem(
                        characterSheetId = it.characterSheetId,
                        inventoryId = it.inventoryId,
                    )
                }
                focus.clearFocus(force = true)
            }
        )
    }

    PurseDialog(
        dialog = purseViewModel.purseDialog.collectAsState(),
        onDismissRequest = {
            purseViewModel.hidePurseDialog()
        },
        onSwapSign = {
            purseViewModel.swapPurseSign()
        },
        onConfirm = {
            scope.launch {
                if (purseViewModel.confirmPurse(dialog = it)) {
                    purseViewModel.hidePurseDialog()
                }
            }
        }
    )

    InventoryDialog(
        dialog = inventoryDialogViewModel.inventoryDialog.collectAsState(),
        onDismissRequest = {
            inventoryDialogViewModel.hideInventoryDialog()
        },
        onItem = { dialog, itemId ->
            itemDetailDialogViewModel.showItemDialog(
                characterSheetId = dialog.characterSheetId,
                inventoryId = null,
                itemId = itemId,
            )
        },
    )

    ItemDetailDialog(
        dialog = itemDetailDialogViewModel.itemDialog.collectAsState(),
        onDismissRequest = {
            itemDetailDialogViewModel.hideItemDialog()
        },
        onAddItem = { dialog ->
            scope.launch {
                val result = itemDetailDialogViewModel.onAddInventoryItem(
                    dialog = dialog,
                )
                if (result) {
                    itemDetailDialogViewModel.hideItemDialog()
                }
            }
        },
        onConfirm = { dialog ->
            scope.launch {
                val result = itemDetailDialogViewModel.changeInventoryItemQuantity(
                    dialog = dialog,
                )
                if (result) {
                    itemDetailDialogViewModel.hideItemDialog()
                }
            }
        },
        onEquip = { dialog ->
            scope.launch {
                val result = itemDetailDialogViewModel.equipInventoryItem(
                    characterSheetId = dialog.characterSheetId,
                    inventoryId = dialog.inventoryId,
                )
                if (result) {
                    itemDetailDialogViewModel.hideItemDialog()
                }
            }
        },
        onConsume = { dialog ->
            scope.launch {
                val result = itemDetailDialogViewModel.consumeInventoryItem(
                    characterSheetId = dialog.characterSheetId,
                    inventoryId = dialog.inventoryId,
                )
                if (result) {
                    itemDetailDialogViewModel.hideItemDialog()
                }
            }
        },
        onThrow = { dialog ->
            scope.launch {
                val result = itemDetailDialogViewModel.throwInventoryItem(
                    characterSheetId = dialog.characterSheetId,
                    inventoryId = dialog.inventoryId,
                )
                if (result) {
                    itemDetailDialogViewModel.hideItemDialog()
                }
            }
        }
    )

    ErrorSnackHandler(
        error = purseViewModel.error,
    )
    ErrorSnackHandler(
        error = itemDetailDialogViewModel.error,
    )
}

@Composable
private fun CharacterDetailInventoryContent(
    modifier: Modifier = Modifier,
    paddings: PaddingValues,
    spacing: Dp,
    inventory: CharacterDetailInventoryUio,
    onPurse: (String) -> Unit,
    onItem: (InventoryItemUio) -> Unit,
    onConsume: (InventoryItemUio) -> Unit,
    onEquip: (InventoryItemUio) -> Unit,
    onAddItem: (String) -> Unit,
) {
    val addItemAction = inventory.addItemAction.collectAsState()
    Box(
        modifier = modifier,
    ) {
        LazyColumn(
            modifier = Modifier.matchParentSize(),
            contentPadding = paddings.plus(addItemAction, PaddingValues(bottom = 56.dp)),
            verticalArrangement = Arrangement.spacedBy(space = spacing),
        ) {
            item(
                key = "purse",
            ) {
                Row(
                    modifier = Modifier
                        .animateItem()
                        .fillMaxWidth(),
                    verticalAlignment = Alignment.Bottom,
                    horizontalArrangement = Arrangement.spacedBy(space = spacing),
                ) {
                    InventoryPurse(
                        purse = inventory.purse,
                        onPurse = { onPurse(inventory.characterSheetId) },
                    )
                    Spacer(
                        modifier = Modifier.weight(weight = 1f)
                    )
                    AnimatedContent(
                        targetState = inventory.showFilter.collectAsState().value,
                    ) {
                        when (it) {
                            true -> LwaTextField(
                                colors = LwaTextFieldColors(
                                    backgroundColor = MaterialTheme.lwa.colorScheme.elevated.base2dp,
                                ),
                                field = inventory.filter,
                                trailingIcon = {
                                    val value = inventory.filter.valueFlow.collectAsState()
                                    androidx.compose.animation.AnimatedVisibility(
                                        visible = value.value.isNotBlank(),
                                        enter = fadeIn(),
                                        exit = fadeOut(),
                                    ) {
                                        IconButton(
                                            onClick = { inventory.filter.onValueChange.invoke("") },
                                        ) {
                                            Icon(
                                                painter = painterResource(Res.drawable.ic_cancel_24dp),
                                                tint = MaterialTheme.lwa.colorScheme.base.primary,
                                                contentDescription = null,
                                            )
                                        }
                                    }
                                }
                            )

                            else -> Box(
                                modifier = Modifier
                                    .clip(shape = MaterialTheme.lwa.shapes.base.small)
                                    .clickable { (inventory.showFilter as? MutableStateFlow<Boolean>)?.value = true }
                                    .size(size = 32.dp),
                                contentAlignment = Alignment.Center,
                            ) {
                                Icon(
                                    painter = painterResource(Res.drawable.ic_filter_list_24dp),
                                    tint = MaterialTheme.lwa.colorScheme.base.primary,
                                    contentDescription = null
                                )
                            }
                        }
                    }
                }
            }
            items(
                items = inventory.items,
                key = { it.inventoryId },
            ) {
                InventoryItem(
                    modifier = Modifier.animateItem(),
                    item = it,
                    onClick = { onItem(it) },
                    onConsume = { onConsume(it) },
                    onEquip = { onEquip(it) },
                )
            }
        }
        AnimatedVisibility(
            modifier = Modifier
                .align(alignment = Alignment.BottomEnd)
                .padding(paddingValues = paddings),
            visible = addItemAction.value,
            enter = fadeIn(),
            exit = fadeOut(),
        ) {
            Row(
                horizontalArrangement = Arrangement.SpaceBetween,
            ) {
                Button(
                    colors = LwaButtonColors(),
                    elevation = ButtonDefaults.elevation(4.dp),
                    shape = CircleShape,
                    onClick = { onAddItem(inventory.characterSheetId) },
                ) {
                    Text(
                        modifier = Modifier.padding(end = 4.dp),
                        text = stringResource(Res.string.character__inventory__add_to_inventory__action),
                    )
                    Icon(
                        imageVector = Icons.Default.Add,
                        contentDescription = null,
                    )
                }
            }
        }
    }
}

@Stable
@Composable
fun PaddingValues.plus(
    state: State<Boolean>,
    other: PaddingValues,
): PaddingValues {
    val direction = LocalLayoutDirection.current
    val sum by remember(this, other, direction, state) {
        derivedStateOf {
            if (state.value) {
                PaddingValues(
                    start = calculateStartPadding(direction) + other.calculateStartPadding(direction),
                    top = calculateTopPadding() + other.calculateTopPadding(),
                    end = calculateEndPadding(direction) + other.calculateEndPadding(direction),
                    bottom = calculateBottomPadding() + other.calculateBottomPadding(),
                )
            } else {
                this
            }
        }
    }
    return sum
}