package com.pixelized.desktop.lwa.ui.screen.admin.action

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
import com.pixelized.desktop.lwa.ui.composable.confirmation.ConfirmationDialogUio
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackUio
import com.pixelized.desktop.lwa.ui.composable.textfield.createLwaTextField
import com.pixelized.desktop.lwa.ui.composable.textfield.createLwaTextFieldFlow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.game_master__actions__campaign_scene__title
import lwacharactersheet.composeapp.generated.resources.game_master__actions__hide_npc__description
import lwacharactersheet.composeapp.generated.resources.game_master__actions__hide_npc__title
import lwacharactersheet.composeapp.generated.resources.game_master__actions__hide_player__description
import lwacharactersheet.composeapp.generated.resources.game_master__actions__hide_player__title
import lwacharactersheet.composeapp.generated.resources.game_master__actions__on_server_sync__description
import lwacharactersheet.composeapp.generated.resources.game_master__actions__on_server_sync__title
import lwacharactersheet.composeapp.generated.resources.game_master__actions__party_heal__description
import lwacharactersheet.composeapp.generated.resources.game_master__actions__party_heal__title
import lwacharactersheet.composeapp.generated.resources.game_master__actions__show_npc__description
import lwacharactersheet.composeapp.generated.resources.game_master__actions__show_npc__title
import lwacharactersheet.composeapp.generated.resources.game_master__actions__show_player__description
import lwacharactersheet.composeapp.generated.resources.game_master__actions__show_player__title
import org.jetbrains.compose.resources.getString

class GMActionViewModel(
    private val actionUseCase: GMActionUseCase,
    campaignRepository: CampaignRepository,
) : ViewModel() {

    private val _error = MutableSharedFlow<ErrorSnackUio>()
    val error: SharedFlow<ErrorSnackUio> get() = _error

    val actions: StateFlow<ActionPageUio?> = campaignRepository.campaignFlow()
        .map {
            ActionPageUio(
                party = it.options.showParty,
                npc = it.options.showNpcs,
            )
        }
        .distinctUntilChanged()
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.Lazily,
            initialValue = null,
        )

    private val _validationDialog = MutableStateFlow<ConfirmationDialogUio?>(null)
    val validationDialog: StateFlow<ConfirmationDialogUio?> = _validationDialog

    private val _editDialog = MutableStateFlow<GMEditDialogUio?>(null)
    val editDialog: StateFlow<GMEditDialogUio?> = _editDialog

    suspend fun onServerSync() {
        showConfirmationDialog(
            title = getString(Res.string.game_master__actions__on_server_sync__title),
            description = getString(Res.string.game_master__actions__on_server_sync__description),
            onConfirmRequest = {
                try {
                    actionUseCase.invalidateServerCache()
                } catch (exception: Exception) {
                    val message = ErrorSnackUio.from(exception = exception)
                    _error.emit(message)
                }
            },
            onDismissRequest = {
                _validationDialog.value = null
            }
        )
    }

    suspend fun onEditSession() {
        showEditDialog(
            title = getString(Res.string.game_master__actions__campaign_scene__title),
            value = actionUseCase.currentSceneTitle(),
            onConfirmRequest = {
                try {
                    actionUseCase.updateSceneTitle(title = it)
                } catch (exception: Exception) {
                    val message = ErrorSnackUio.from(exception = exception)
                    _error.emit(message)
                }
            },
            onDismissRequest = {
                _editDialog.value = null
            },
        )
    }

    suspend fun onPartyHeal() {
        showConfirmationDialog(
            title = getString(Res.string.game_master__actions__party_heal__title),
            description = getString(Res.string.game_master__actions__party_heal__description),
            onConfirmRequest = {
                try {
                    actionUseCase.healPlayerParty()
                } catch (exception: Exception) {
                    val message = ErrorSnackUio.from(exception = exception)
                    _error.emit(message)
                }
            },
        )
    }

    suspend fun onPlayerVisibility() {
        showConfirmationDialog(
            title = when (actions.value?.party) {
                true -> getString(Res.string.game_master__actions__hide_player__title)
                else -> getString(Res.string.game_master__actions__show_player__title)
            },
            description = when (actions.value?.party) {
                true -> getString(Res.string.game_master__actions__hide_player__description)
                else -> getString(Res.string.game_master__actions__show_player__description)
            },
            onConfirmRequest = {
                try {
                    actionUseCase.togglePlayerVisibility()
                } catch (exception: Exception) {
                    val message = ErrorSnackUio.from(exception = exception)
                    _error.emit(message)
                }
            },
        )
    }

    suspend fun onNpcVisibility() {
        showConfirmationDialog(
            title = when (actions.value?.npc) {
                true -> getString(Res.string.game_master__actions__hide_npc__title)
                else -> getString(Res.string.game_master__actions__show_npc__title)
            },
            description = when (actions.value?.npc) {
                true -> getString(Res.string.game_master__actions__hide_npc__description)
                else -> getString(Res.string.game_master__actions__show_npc__description)
            },
            onConfirmRequest = {
                try {
                    actionUseCase.toggleNpcVisibility()
                } catch (exception: Exception) {
                    val message = ErrorSnackUio.from(exception = exception)
                    _error.emit(message)
                }
            },
        )
    }

    private inline fun showConfirmationDialog(
        title: String,
        description: String,
        crossinline onConfirmRequest: suspend () -> Unit,
        crossinline onDismissRequest: () -> Unit = { _validationDialog.value = null },
    ) {
        _validationDialog.value = ConfirmationDialogUio(
            title = title,
            description = description,
            onConfirmRequest = {
                viewModelScope.launch {
                    onConfirmRequest()
                    onDismissRequest()
                }
            },
            onDismissRequest = {
                onDismissRequest()
            },
        )
    }

    private inline fun showEditDialog(
        title: String,
        value: String,
        crossinline onConfirmRequest: suspend (String) -> Unit,
        crossinline onDismissRequest: () -> Unit = { _editDialog.value = null },
    ) {
        val edit = createLwaTextFieldFlow(
            label = value,
        )
        _editDialog.value = GMEditDialogUio(
            title = title,
            edit = edit.createLwaTextField(),
            onConfirmRequest = {
                viewModelScope.launch {
                    onConfirmRequest(edit.valueFlow.value)
                    onDismissRequest()
                }
            },
            onDismissRequest = {
                onDismissRequest()
            },
        )
    }
}