package com.pixelized.desktop.lwa.ui.screen.admin.character.edit

import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
import com.pixelized.desktop.lwa.repository.tag.TagRepository
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackUio
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.gamemaster.GMCharacterEditDestination
import com.pixelized.desktop.lwa.ui.screen.admin.character.list.GMCharacterFactory.Companion.NPC_ID
import com.pixelized.desktop.lwa.ui.screen.admin.character.list.GMCharacterFactory.Companion.PLAYER_ID
import com.pixelized.desktop.lwa.ui.screen.admin.common.tag.GMTagUio
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

class GMCharacterEditViewModel(
    private val characterSheetRepository: CharacterSheetRepository,
    private val tagRepository: TagRepository,
    private val factory: GMCharacterEditFactory,
    savedStateHandle: SavedStateHandle,
) : ViewModel() {
    private val argument = GMCharacterEditDestination.Argument(savedStateHandle)

    private val _form = MutableStateFlow<GMCharacterEditPageUio?>(null)
    val form: StateFlow<GMCharacterEditPageUio?> get() = _form

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

    init {
        viewModelScope.launch {
            _form.value = factory.createForm(
                scope = this,
                sheet = characterSheetRepository.characterDetail(argument.characterSheetId),
                tags = tagRepository.charactersTags().filterNot {
                    it.id == PLAYER_ID || it.id == NPC_ID
                },
            )
        }
    }

    suspend fun save(): Boolean {
        try {
            val characterSheet = factory.convertIntoModel(
                sheet = characterSheetRepository.characterDetail(argument.characterSheetId),
                form = _form.value ?: error("Form is empty")
            )
            characterSheetRepository.updateCharacter(
                sheet = characterSheet,
                create = argument.characterSheetId == null,
            )
            return true
        } catch (exception: Exception) {
            val message = ErrorSnackUio.from(exception)
            _error.emit(message)
            return false
        }
    }

    suspend fun saveAs(
        overrideCharacterSheetId: String?,
        overrideCharacterName: String?,
    ): Boolean {
        try {
            if (overrideCharacterSheetId == null) {
                error("characterSheetId should not be null")
            }
            if (overrideCharacterName == null) {
                error("character name should not be null")
            }
            val characterSheet = factory.convertIntoModel(
                sheet = characterSheetRepository.characterDetail(argument.characterSheetId),
                form = _form.value ?: error("Form is empty")
            ).copy(
                id = overrideCharacterSheetId,
                name = overrideCharacterName,
            )
            characterSheetRepository.updateCharacter(
                sheet = characterSheet,
                create = true,
            )
            return true
        } catch (exception: Exception) {
            val message = ErrorSnackUio.from(exception)
            _error.emit(message)
            return false
        }
    }

    fun addTag(tag: GMTagUio) {
        _form.value?.tags?.update { tags ->
            tags.toMutableList().also {
                val index = it.indexOf(tag)
                if (index > -1) {
                    it[index] = tag.copy(highlight = tag.highlight.not())
                }
            }
        }
    }

    suspend fun deleteSpecialSkill(
        index: Int,
    ) {
        _form.update { form ->
            form?.copy(
                specialSkills = form.specialSkills.toMutableList().also {
                    it.removeAt(index)
                },
            )
        }
    }

    suspend fun addSpecialSkill() {
        _form.update { form ->
            form?.copy(
                specialSkills = form.specialSkills.toMutableList().also {
                    it.add(factory.createSkill(skill = null))
                },
            )
        }
    }

    suspend fun deleteMagicSkill(
        index: Int,
    ) {
        _form.update { form ->
            form?.copy(
                magicSkills = form.magicSkills.toMutableList().also {
                    it.removeAt(index)
                },
            )
        }
    }

    suspend fun addMagicSkill() {
        _form.update { form ->
            form?.copy(
                magicSkills = form.magicSkills.toMutableList().also {
                    it.add(factory.createSkill(skill = null))
                },
            )
        }
    }

    suspend fun deleteAction(
        index: Int,
    ) {
        _form.update { form ->
            form?.copy(
                actions = form.actions.toMutableList().also {
                    it.removeAt(index)
                },
            )
        }
    }

    suspend fun addAction() {
        delay(150)
        _form.update { form ->
            form?.copy(
                actions = form.actions.toMutableList().also {
                    it.add(factory.createAction(action = null))
                },
            )
        }
    }

    fun toggleOccupation(
        skillId: String,
    ) {
        val common = _form.value?.commonSkills ?: emptyList()
        val special = _form.value?.specialSkills ?: emptyList()
        val magics = _form.value?.magicSkills ?: emptyList()
        (common + special + magics)
            .firstOrNull { it.id.valueFlow.value == skillId }
            ?.let {
                it.occupation.onCheckedChange(it.occupation.checked.value.not())
            }
    }
}