package com.prodhack.moscow2025.presentation.screens.fillProfile

import android.content.ContentUris
import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import android.provider.MediaStore
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.viewModelScope
import androidx.paging.map
import coil.ImageLoader
import coil.request.ImageRequest
import com.prodhack.moscow2025.data.data_providers.PhoneNumberPatternsProvider
import com.prodhack.moscow2025.domain.interfaces.GalleryRepository
import com.prodhack.moscow2025.domain.models.AuthField
import com.prodhack.moscow2025.domain.models.UpdateUserData
import com.prodhack.moscow2025.domain.usecase.GetDefaultPhoneNumberPatternUseCase
import com.prodhack.moscow2025.domain.usecase.auth.UpdateUserUseCase
import com.prodhack.moscow2025.domain.usecase.auth.ValidateFieldsUseCase
import com.prodhack.moscow2025.presentation.utils.UIState
import com.prodhack.moscow2025.presentation.utils.base.BaseViewModel
import com.prodhack.moscow2025.presentation.utils.convertNumberToPattern
import com.prodhack.moscow2025.presentation.utils.toByteArray
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.koin.android.annotation.KoinViewModel

data class FillProfileFormState(
	val firstName: String = "",
	val lastName: String = "",
	val phone: String = "",
	val avatar: ByteArray? = null,
	val errors: Map<AuthField, String> = emptyMap()
) {
	override fun equals(other: Any?): Boolean {
		if (this === other) return true
		if (javaClass != other?.javaClass) return false

		other as FillProfileFormState

		if (firstName != other.firstName) return false
		if (lastName != other.lastName) return false
		if (phone != other.phone) return false
		if (!avatar.contentEquals(other.avatar)) return false
		if (errors != other.errors) return false

		return true
	}

	override fun hashCode(): Int {
		var result = firstName.hashCode()
		result = 31 * result + lastName.hashCode()
		result = 31 * result + phone.hashCode()
		result = 31 * result + (avatar?.contentHashCode() ?: 0)
		result = 31 * result + errors.hashCode()
		return result
	}
}

@KoinViewModel
class FillProfileViewModel(
	private val updateUserUseCase: UpdateUserUseCase,
	private val validateFieldsUseCase: ValidateFieldsUseCase,
	private val getDefaultPhoneNumberPatternUseCase: GetDefaultPhoneNumberPatternUseCase,
	private val galleryRepository: GalleryRepository
) : BaseViewModel() {
	private val _formStateFillProfile = MutableStateFlow(FillProfileFormState())
	val formStateFillProfile: StateFlow<FillProfileFormState> = _formStateFillProfile

	private val _profileFillState = MutableUIStateFlow<String>()
	val profileFillState: StateFlow<UIState<String>> = _profileFillState

	fun onFirstNameChange(value: String) {
		_formStateFillProfile.update {
			it.copy(
				firstName = value,
				errors = it.errors - AuthField.FirstName
			)
		}
	}

	fun onLastNameChange(value: String) {
		_formStateFillProfile.update {
			it.copy(
				lastName = value,
				errors = it.errors - AuthField.LastName
			)
		}
	}

	fun onPhoneChange(value: String) {
		val maxDigits = currentPattern.value?.pattern?.count { it == '0' } ?: Int.MAX_VALUE
		val digits = value.filter { it.isDigit() }.take(maxDigits)
		_formStateFillProfile.update {
			it.copy(
				phone = digits,
				errors = it.errors - AuthField.Phone
			)
		}
	}


	val galleryItems = galleryRepository.getImagesIds().map {
		it.map { id ->
			ContentUris.withAppendedId(
				MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
				id
			)
		}
	}

	fun post(context: Context) {
		viewModelScope.launch {
			post(
				(ImageLoader(context).execute(
					ImageRequest.Builder(context)
						.data(currentPhoto).build()
				).drawable as BitmapDrawable).bitmap
			)
		}
	}

	fun post(bitmap: Bitmap) {
		viewModelScope.launch {
			_formStateFillProfile.update {
				it.copy(
					avatar = bitmap.toByteArray()
				)
			}
		}
	}

	fun clearAvatar() {
		viewModelScope.launch {
			_formStateFillProfile.update {
				it.copy(
					avatar = null
				)
			}
		}
	}

	var currentPhoto: Uri? = null

	fun selectImage(photo: Uri) {
		currentPhoto = photo
	}


	val currentPattern = mutableStateOf<UIPhoneNumberPattern?>(null)

	val phoneNumberPatterns = mutableStateListOf<UIPhoneNumberPattern>()


	fun update() {
		// Load default pattern
		currentPattern.value = getDefaultPhoneNumberPatternUseCase.execute()?.mapToUI()

		// Load all phone number patterns
		phoneNumberPatterns.clear()
		phoneNumberPatterns.addAll(PhoneNumberPatternsProvider.phoneNumberPatterns.map { it.mapToUI() })
	}

	fun submit() {
		viewModelScope.launch {
			val validation = validateFieldsUseCase.validateFillProfile(
				firstName = _formStateFillProfile.value.firstName,
				lastName = _formStateFillProfile.value.lastName,
				phone = _formStateFillProfile.value.phone,
				chosenPattern = currentPattern.value?.mapToDomain()
			)

			if (!validation.isValid) {
				_formStateFillProfile.update { it.copy(errors = validation.errors) }
				return@launch
			}

			_profileFillState.emit(UIState.Loading())

			val result = updateUserUseCase(
				UpdateUserData(
					firstName = _formStateFillProfile.value.firstName,
					lastName = _formStateFillProfile.value.lastName,
					phone = currentPattern.value?.mapToDomain()?.let { phoneNumberPattern ->
						convertNumberToPattern(
							phoneNumberPattern,
							_formStateFillProfile.value.phone
						)
					}
				)
			)

			result.map { it.id }.collectRequest(_profileFillState)
		}
	}

	init {
		update()
	}
}
