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

import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.ContentTransform
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.PagerState
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.LayoutDirection
import com.pixelized.desktop.lwa.LocalRollHostState
import com.pixelized.desktop.lwa.ui.composable.blur.BlurContentController
import com.pixelized.desktop.lwa.ui.composable.character.alterteration.CharacterSheetAlterationDialogViewModel
import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterSheetCharacteristicDialogUio
import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterSheetCharacteristicDialogViewModel
import com.pixelized.desktop.lwa.ui.composable.character.diminished.CharacterSheetDiminishedDialogViewModel
import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.header.CharacterDetailHeader
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.header.CharacterDetailHeaderUio
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.CharacterDetailInventory
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.CharacterDetailInventoryUio
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheet
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetUio
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.item.CharacterDetailSheetActionUio
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.item.CharacterDetailSheetCharacteristicUio
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.item.CharacterDetailSheetSkillUio
import com.pixelized.desktop.lwa.ui.theme.lwa
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch

@Stable
data class CharacterDetailPanelUio(
    val characterSheetId: String?,
    val panel: DetailPanelUio,
    val header: StateFlow<CharacterDetailHeaderUio?>,
    val sheet: StateFlow<CharacterDetailSheetUio?>,
    val inventory: StateFlow<CharacterDetailInventoryUio?>,
)

@Stable
enum class DetailPanelUio {
    Sheet,
    Inventory,
}

@Composable
fun CharacterDetailPanel(
    modifier: Modifier = Modifier,
    transitionSpec: AnimatedContentTransitionScope<CharacterDetailPanelUio>.() -> ContentTransform = rememberTransitionAnimation(),
    detailPanelViewModel: CharacterDetailPanelViewModel,
    characteristicDialogViewModel: CharacterSheetCharacteristicDialogViewModel,
    characterDiminishedViewModel: CharacterSheetDiminishedDialogViewModel,
    alterationViewModel: CharacterSheetAlterationDialogViewModel,
    onLevelUp: (String) -> Unit,
) {
    val roll = LocalRollHostState.current
    val scope = rememberCoroutineScope()
    val pager = rememberPagerState(initialPage = 0) { DetailPanelUio.entries.size }
    val detail: State<CharacterDetailPanelUio> = detailPanelViewModel.detail.collectAsState()

    LaunchedEffect(Unit) {
        detailPanelViewModel.detail
            .map { it.panel }
            .distinctUntilChanged()
            .onEach { pager.animateScrollToPage(page = it.ordinal) }
            .launchIn(this)
    }

    CharacterDetailAnimatedPanel(
        modifier = modifier,
        pagerState = pager,
        detail = detail,
        transitionSpec = transitionSpec,
        onDismissRequest = {
            detailPanelViewModel.hideCharacter()
        },
        onLevelUp = onLevelUp,
        onSheet = { characterSheetId ->
            scope.launch {
                detailPanelViewModel.showCharacter(
                    characterSheetId = characterSheetId,
                    panel = DetailPanelUio.Sheet,
                )
            }
        },
        onInventory = { characterSheetId ->
            scope.launch {
                detailPanelViewModel.showCharacter(
                    characterSheetId = characterSheetId,
                    panel = DetailPanelUio.Inventory,
                )
            }
        },
        onAlteration = {
            alterationViewModel.show(characterSheetId = it)
        },
        onDiminished = {
            scope.launch {
                characterDiminishedViewModel.showDiminishedDialog(
                    characterSheetId = it
                )
            }
        },
        onHp = {
            scope.launch {
                characteristicDialogViewModel.showSubCharacteristicDialog(
                    characterSheetId = it,
                    characteristic = CharacterSheetCharacteristicDialogUio.Characteristic.Damage,
                )
            }
        },
        onPp = {
            scope.launch {
                characteristicDialogViewModel.showSubCharacteristicDialog(
                    characterSheetId = it,
                    characteristic = CharacterSheetCharacteristicDialogUio.Characteristic.Fatigue,
                )
            }
        },
        onReflex = {
            scope.launch {
                val result = roll.showRollOverlay(roll = it)
                println("result: $result")
            }
        },
        onCharacteristic = {
            scope.launch {
                val result = roll.showRollOverlay(roll = it.roll)
                println("result: $result")
            }
        },
        onSkill = {
            scope.launch {
                val result = roll.showRollOverlay(roll = it.roll)
                detailPanelViewModel.onSkillUse(
                    skillId = it.skillId,
                    result = result,
                )
                println("result: $result")
            }
        },
        onUseSkill = {
            scope.launch {
                detailPanelViewModel.onSkillUse(
                    skillId = it.skillId,
                    used = it.used,
                )
            }
        },
        onAction = {
            scope.launch {
                val result = roll.showRollOverlay(roll = it.roll)
                println("result: $result")
            }
        }
    )
}

@Composable
fun CharacterDetailAnimatedPanel(
    modifier: Modifier = Modifier,
    shape: Shape = MaterialTheme.lwa.shapes.panel,
    pagerState: PagerState,
    detail: State<CharacterDetailPanelUio>,
    transitionSpec: AnimatedContentTransitionScope<CharacterDetailPanelUio>.() -> ContentTransform,
    onDismissRequest: () -> Unit,
    onLevelUp: (characterSheetId: String) -> Unit,
    onSheet: (characterSheetId: String) -> Unit,
    onInventory: (characterSheetId: String) -> Unit,
    onAlteration: (characterSheetId: String) -> Unit,
    onDiminished: (characterSheetId: String) -> Unit,
    onHp: (characterSheetId: String) -> Unit,
    onPp: (characterSheetId: String) -> Unit,
    onReflex: (RollAction.Uio) -> Unit,
    onCharacteristic: (CharacterDetailSheetCharacteristicUio) -> Unit,
    onSkill: (CharacterDetailSheetSkillUio) -> Unit,
    onUseSkill: (CharacterDetailSheetSkillUio) -> Unit,
    onAction: (CharacterDetailSheetActionUio) -> Unit,
) {
    Box(
        modifier = modifier,
    ) {
        AnimatedContent(
            modifier = Modifier.matchParentSize(),
            targetState = detail.value,
            transitionSpec = transitionSpec,
        ) {
            when {
                it.characterSheetId == null -> Box(
                    modifier = Modifier.matchParentSize(),
                )

                else -> {
                    Box(
                        modifier = Modifier.matchParentSize(),
                    ) {
                        CharacterDetailContent(
                            modifier = Modifier.matchParentSize(),
                            pagerState = pagerState,
                            detail = it,
                            shape = shape,
                            onDismissRequest = onDismissRequest,
                            onLevelUp = { onLevelUp(it.characterSheetId) },
                            onSheet = { onSheet(it.characterSheetId) },
                            onInventory = { onInventory(it.characterSheetId) },
                            onAlteration = { onAlteration(it.characterSheetId) },
                            onDiminished = { onDiminished(it.characterSheetId) },
                            onHp = { onHp(it.characterSheetId) },
                            onPp = { onPp(it.characterSheetId) },
                            onReflex = onReflex,
                            onCharacteristic = onCharacteristic,
                            onSkill = onSkill,
                            onUseSkill = onUseSkill,
                            onAction = onAction,
                        )
                    }
                }
            }
        }
    }
}

@Composable
fun CharacterDetailContent(
    modifier: Modifier = Modifier,
    shape: Shape = MaterialTheme.lwa.shapes.panel,
    detail: CharacterDetailPanelUio,
    pagerState: PagerState,
    onLevelUp: () -> Unit,
    onSheet: () -> Unit,
    onInventory: () -> Unit,
    onAlteration: () -> Unit,
    onDismissRequest: () -> Unit,
    onDiminished: () -> Unit,
    onHp: () -> Unit,
    onPp: () -> Unit,
    onReflex: (RollAction.Uio) -> Unit,
    onCharacteristic: (CharacterDetailSheetCharacteristicUio) -> Unit,
    onSkill: (CharacterDetailSheetSkillUio) -> Unit,
    onUseSkill: (CharacterDetailSheetSkillUio) -> Unit,
    onAction: (CharacterDetailSheetActionUio) -> Unit,
) {
    Surface(
        modifier = modifier,
        shape = shape,
        color = MaterialTheme.lwa.colorScheme.elevated.base1dp,
    ) {
        Column {
            CharacterDetailHeader(
                modifier = Modifier
                    .background(color = MaterialTheme.lwa.colorScheme.elevated.base2dp)
                    .fillMaxWidth(),
                header = detail.header.collectAsState(),
                onDismissRequest = onDismissRequest,
                onLevelUp = onLevelUp,
                onSheet = onSheet,
                onInventory = onInventory,
                onAlteration = onAlteration,
                onDiminished = onDiminished,
                onHp = onHp,
                onPp = onPp,
                onReflex = onReflex,
            )
            HorizontalPager(
                modifier = Modifier.weight(1f),
                state = pagerState,
            ) { page ->
                when (page) {
                    DetailPanelUio.Sheet.ordinal -> {
                        CharacterDetailSheet(
                            modifier = Modifier.fillMaxSize(),
                            sheet = detail.sheet.collectAsState(),
                            onCharacteristic = onCharacteristic,
                            onSkill = onSkill,
                            onUseSkill = onUseSkill,
                            onAction = onAction,
                        )
                    }

                    DetailPanelUio.Inventory.ordinal -> {
                        CharacterDetailInventory(
                            modifier = Modifier.fillMaxSize(),
                            inventory = detail.inventory.collectAsState(),
                        )
                    }
                }
            }
        }
    }
}

@Composable
@Stable
fun rememberTransitionAnimation(
    direction: LayoutDirection = LayoutDirection.Rtl,
): AnimatedContentTransitionScope<CharacterDetailPanelUio>.() -> ContentTransform {
    return remember {
        val mul = if (direction == LayoutDirection.Rtl) 1 else -1
        {
            if (initialState.characterSheetId != targetState.characterSheetId) {
                val enter = fadeIn() + slideInHorizontally { mul * it / 2 }
                val exit = fadeOut() + slideOutHorizontally { mul * it / 2 }
                enter togetherWith exit
            } else {
                EnterTransition.None togetherWith ExitTransition.None
            }
        }
    }
}