package com.horrortv.app.presentation.search

import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.horrortv.app.domain.model.AppError
import com.horrortv.app.domain.model.Movie
import com.horrortv.app.domain.repository.MovieRepository
import com.horrortv.app.domain.repository.Result
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import javax.inject.Inject

@OptIn(FlowPreview::class)
@HiltViewModel
class SearchViewModel @Inject constructor(
    private val repository: MovieRepository
) : ViewModel() {

    private companion object {
        const val TAG = "SearchViewModel"
        const val DEBOUNCE_DELAY_MS = 300L
    }

    private val _uiState = MutableStateFlow(SearchUiState())
    val uiState: StateFlow<SearchUiState> = _uiState.asStateFlow()

    private val _searchQuery = MutableStateFlow("")
    val searchQuery: StateFlow<String> = _searchQuery.asStateFlow()

    private var searchJob: Job? = null

    init {
        _searchQuery
            .debounce(DEBOUNCE_DELAY_MS)
            .onEach { query ->
                if (query.isNotEmpty()) {
                    performSearch(query)
                }
            }
            .launchIn(viewModelScope)
    }

    fun updateQuery(query: String) {
        val trimmedQuery = query.trim()
        _searchQuery.value = trimmedQuery

        if (trimmedQuery.isEmpty()) {
            searchJob?.cancel()
            _uiState.update { it.copy(movies = emptyList(), directMovie = null, error = null, isLoading = false) }
        }
    }

    private fun performSearch(query: String) {
        if (query.isEmpty()) return

        searchJob?.cancel()
        searchJob = viewModelScope.launch {
            Log.d(TAG, "Searching for: $query")
            _uiState.update { it.copy(isLoading = true, error = null, directMovie = null) }

            if (query.isValidImdbId()) {
                searchById(query)
            } else {
                searchByName(query)
            }
        }
    }

    private suspend fun searchById(imdbId: String) {
        val result = repository.getMovieById(imdbId)

        when (result) {
            is Result.Success -> {
                val movie = result.data
                if (movie != null) {
                    Log.d(TAG, "Found movie: ${movie.title}")
                    _uiState.update { it.copy(directMovie = movie, movies = emptyList(), isLoading = false) }
                } else {
                    Log.w(TAG, "Movie not found: $imdbId")
                    _uiState.update {
                        it.copy(
                            isLoading = false,
                            error = AppError.ValidationError(
                                userMessage = "No se encontró la película con ID: $imdbId",
                                debugMessage = "Movie not found for IMDB ID",
                                field = "imdbId"
                            )
                        )
                    }
                }
            }
            is Result.Error -> {
                Log.e(TAG, "Error searching by ID: ${result.error.debugMessage}")
                _uiState.update { it.copy(isLoading = false, error = result.error) }
            }
        }
    }

    private suspend fun searchByName(query: String) {
        val result = repository.searchMovies(query)

        when (result) {
            is Result.Success -> {
                val movies = result.data
                Log.d(TAG, "Found ${movies.size} movies")
                _uiState.update { it.copy(movies = movies, directMovie = null, isLoading = false) }
            }
            is Result.Error -> {
                Log.e(TAG, "Error searching: ${result.error.debugMessage}")
                _uiState.update { it.copy(isLoading = false, error = result.error) }
            }
        }
    }

    fun retry() {
        val currentQuery = _searchQuery.value
        if (currentQuery.isNotEmpty()) {
            performSearch(currentQuery)
        }
    }

    fun clearResults() {
        searchJob?.cancel()
        _searchQuery.value = ""
        _uiState.update { SearchUiState() }
    }

    fun clearError() {
        _uiState.update { it.copy(error = null) }
    }
}

data class SearchUiState(
    val movies: List<Movie> = emptyList(),
    val directMovie: Movie? = null,
    val isLoading: Boolean = false,
    val error: AppError? = null
)

fun String.isValidImdbId(): Boolean {
    return com.horrortv.app.util.Constants.IMDB_ID_PATTERN.matches(this)
}