package com.prodhack.moscow2025.presentation.screens.createResume

import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.snapshotFlow
import androidx.lifecycle.viewModelScope
import com.prodhack.moscow2025.domain.models.Education
import com.prodhack.moscow2025.domain.models.EducationGrades
import com.prodhack.moscow2025.domain.models.ExperienceType
import com.prodhack.moscow2025.domain.models.Project
import com.prodhack.moscow2025.domain.models.ResumeCreationModel
import com.prodhack.moscow2025.domain.models.ResumeField
import com.prodhack.moscow2025.domain.models.ResumeModel
import com.prodhack.moscow2025.domain.models.WorkExperience
import com.prodhack.moscow2025.domain.usecase.auth.ValidateFieldsUseCase
import com.prodhack.moscow2025.domain.usecase.resumes.PostResumeUseCase
import com.prodhack.moscow2025.domain.usecase.resumes.SuggestSkillsUseCase
import com.prodhack.moscow2025.presentation.utils.UIState
import com.prodhack.moscow2025.presentation.utils.base.BaseViewModel
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 ResumeFormState(
	val about: String = "",
	val position: String = "",
	val experience: ExperienceType? = null,
	val keySkills: Set<String> = emptySet(),
	val city: String = "",
	val workExperience: List<WorkExperience> = emptyList(),
	val education: List<Education> = emptyList(),
	val projects: List<Project> = emptyList(),
	val errors: Map<ResumeField, String> = emptyMap()
)

@KoinViewModel
class CreateResumeViewModel(
	suggestSkillsUseCase: SuggestSkillsUseCase,
	validateDataUseCase: ValidateFieldsUseCase,
	postResumeUseCase: PostResumeUseCase
) : BaseCreateResumeViewModel(suggestSkillsUseCase, validateDataUseCase, postResumeUseCase)

open class BaseCreateResumeViewModel(
	private val suggestSkillsUseCase: SuggestSkillsUseCase,
	private val validateDataUseCase: ValidateFieldsUseCase,
	private val postResumeUseCase: PostResumeUseCase
) : BaseViewModel() {
	private val _formStateFillResume = MutableStateFlow(ResumeFormState())
	val formStateFillResume: StateFlow<ResumeFormState> = _formStateFillResume

	private val _resumeFillState = MutableUIStateFlow<String>()
	val resumeFillState: StateFlow<UIState<String>> = _resumeFillState
	private var prefilled = false
	private var currId: String? = null

	// Simple fields
	fun onAboutChange(value: String) {
		_formStateFillResume.update {
			it.copy(
				about = value,
				errors = it.errors - ResumeField.About
			)
		}
	}

	fun onPositionChange(value: String) {
		_formStateFillResume.update {
			it.copy(
				position = value,
				errors = it.errors - ResumeField.Position
			)
		}
	}

	fun onCityChange(value: String) {
		_formStateFillResume.update {
			it.copy(
				city = value,
				errors = it.errors - ResumeField.City
			)
		}
	}

	val experienceOptions = ExperienceType.entries.toList()

	fun onExperienceSelect(value: ExperienceType) {
		_formStateFillResume.update {
			it.copy(
				experience = value,
				errors = it.errors - ResumeField.Experience
			)
		}
	}

	// Skills
	fun onAddSkill(value: String) {
		_formStateFillResume.update {
			it.copy(
				keySkills = it.keySkills + value,
				errors = it.errors - ResumeField.KeySkills
			)
		}
		skillSearchQuery.value = ""
	}

	fun onRemoveSkill(value: String) {
		_formStateFillResume.update {
			it.copy(
				keySkills = it.keySkills - value,
				errors = it.errors - ResumeField.KeySkills
			)
		}
	}

	val skillSearchQuery = mutableStateOf("")

	val suggestedSkills = snapshotFlow { skillSearchQuery.value }.map {
		suggestSkillsUseCase(it).getOrNull() ?: emptyList()
	}

	// Experience work

	fun addNewExperience() {
		_formStateFillResume.update {
			it.copy(
				workExperience = it.workExperience + WorkExperience("", "", null)
			)
		}
	}

	fun removeExperience(id: Int) {
		_formStateFillResume.update {
			it.copy(
				workExperience = it.workExperience.filterIndexed { index, _ -> index != id },
				errors = it.errors
						- ResumeField.WorkExperienceDescription(id)
						- ResumeField.WorkExperienceMonthDuration(id)
						- ResumeField.WorkExperiencePlace(id)
			)
		}
	}

	fun changeWorkExperiencePlace(index: Int, value: String) {
		_formStateFillResume.update {
			it.copy(
				workExperience = it.workExperience.mapIndexed { ind, experience ->
					if (ind == index) experience.copy(
						place = value
					) else experience
				},
				errors = it.errors
						- ResumeField.WorkExperiencePlace(index)
			)
		}
	}

	fun changeWorkExperienceMonthDuration(index: Int, value: String) {
		_formStateFillResume.update {
			it.copy(
				workExperience = it.workExperience.mapIndexed { ind, experience ->
					if (ind == index) {
						value.toIntOrNull()?.let {
							experience.copy(
								monthDuration = it
							)
						}
							?: if (value.isEmpty()) experience.copy(monthDuration = null) else experience
					} else experience
				},
				errors = it.errors
						- ResumeField.WorkExperienceDescription(index)
			)
		}
	}

	fun changeWorkExperienceDescription(index: Int, value: String) {
		_formStateFillResume.update {
			it.copy(
				workExperience = it.workExperience.mapIndexed { ind, experience ->
					if (ind == index) experience.copy(
						description = value
					) else experience
				},
				errors = it.errors
						- ResumeField.WorkExperienceDescription(index)
			)
		}
	}

	// Education
	val educationGradeOptions = EducationGrades.entries.toList()

	fun addNewEducation() {
		_formStateFillResume.update {
			it.copy(
				education = it.education + Education(
					place = "",
					grade = EducationGrades.Specialist,
					specialization = "",
					description = ""
				)
			)
		}
	}

	fun removeEducation(id: Int) {
		_formStateFillResume.update {
			it.copy(
				education = it.education.filterIndexed { index, _ -> index != id },
				errors = it.errors
						- ResumeField.EducationSpecialization(id)
						- ResumeField.EducationDescription(id)
						- ResumeField.EducationPlace(id)
						- ResumeField.EducationGrade(id)
			)
		}
	}

	fun changeEducationPlace(index: Int, value: String) {
		_formStateFillResume.update {
			it.copy(
				education = it.education.mapIndexed { ind, education ->
					if (ind == index) education.copy(place = value) else education
				},
				errors = it.errors - ResumeField.EducationPlace(index)
			)
		}
	}

	fun changeEducationGrade(index: Int, value: EducationGrades) {
		_formStateFillResume.update {
			it.copy(
				education = it.education.mapIndexed { ind, education ->
					if (ind == index) education.copy(grade = value) else education
				},
				errors = it.errors - ResumeField.EducationGrade(index)
			)
		}
	}

	fun changeEducationSpecialization(index: Int, value: String) {
		_formStateFillResume.update {
			it.copy(
				education = it.education.mapIndexed { ind, education ->
					if (ind == index) education.copy(specialization = value) else education
				},
				errors = it.errors - ResumeField.EducationSpecialization(index)
			)
		}
	}

	fun changeEducationDescription(index: Int, value: String) {
		_formStateFillResume.update {
			it.copy(
				education = it.education.mapIndexed { ind, education ->
					if (ind == index) education.copy(description = value) else education
				},
				errors = it.errors - ResumeField.EducationDescription(index)
			)
		}
	}

	// Projects
	fun addNewProject() {
		_formStateFillResume.update {
			it.copy(
				projects = it.projects + Project("", "")
			)
		}
	}

	fun removeProject(id: Int) {
		_formStateFillResume.update {
			it.copy(
				projects = it.projects.filterIndexed { index, _ -> index != id },
				errors = it.errors
						- ResumeField.ProjectDescription(id)
						- ResumeField.ProjectName(id)
			)
		}
	}

	fun changeProjectName(index: Int, value: String) {
		_formStateFillResume.update {
			it.copy(
				projects = it.projects.mapIndexed { ind, project ->
					if (ind == index) project.copy(name = value) else project
				},
				errors = it.errors - ResumeField.ProjectName(index)
			)
		}
	}

	fun changeProjectDescription(index: Int, value: String) {
		_formStateFillResume.update {
			it.copy(
				projects = it.projects.mapIndexed { ind, project ->
					if (ind == index) project.copy(description = value) else project
				},
				errors = it.errors - ResumeField.ProjectDescription(index)
			)
		}
	}

	fun prefill(resume: ResumeModel) {
		if (prefilled) return
		prefilled = true
		currId = resume.id
		_formStateFillResume.update {
			it.copy(
				about = resume.about,
				position = resume.position,
				experience = resume.experienceType,
				keySkills = resume.skills.toSet(),
				city = resume.city,
				workExperience = resume.experience,
				education = resume.education,
				projects = resume.projects
			)
		}
	}

	fun submit() {
		viewModelScope.launch {
			val validation = validateDataUseCase.validateResume(
				about = _formStateFillResume.value.about,
				position = _formStateFillResume.value.position,
				experience = _formStateFillResume.value.experience,
				keySkills = _formStateFillResume.value.keySkills.toList(),
				city = _formStateFillResume.value.city,
				workExperience = _formStateFillResume.value.workExperience,
				education = _formStateFillResume.value.education,
				projects = _formStateFillResume.value.projects
			)

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

			_resumeFillState.emit(UIState.Loading())

			val result = postResumeUseCase(
				with(_formStateFillResume.value) {
					ResumeCreationModel(
						position = position,
						about = about,
						skills = keySkills.toList(),
						experienceType = experience!!,
						city = city,
						experience = workExperience,
						education = education,
						projects = projects
					)
				},
				isNew = prefilled.not(),
				resumeId = currId
			)
			result.collectRequest(_resumeFillState)
		}
	}
}
