package com.placeholder.sherpai2.ui.album

import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.placeholder.sherpai2.data.local.dao.ImageDao
import com.placeholder.sherpai2.data.local.dao.ImageTagDao
import com.placeholder.sherpai2.data.local.dao.PersonDao
import com.placeholder.sherpai2.data.local.dao.TagDao
import com.placeholder.sherpai2.data.local.entity.ImageEntity
import com.placeholder.sherpai2.data.local.entity.PersonEntity
import com.placeholder.sherpai2.data.local.entity.PhotoFaceTagEntity
import com.placeholder.sherpai2.data.repository.FaceRecognitionRepository
import com.placeholder.sherpai2.ui.search.DateRange
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import java.util.Calendar
import javax.inject.Inject

/**
 * AlbumViewModel - Display photos from a specific album (tag, person, or time range)
 *
 * Features:
 * - Search within album
 * - Date filtering
 * - Album stats
 * - Export functionality
 */
@HiltViewModel
class AlbumViewModel @Inject constructor(
    savedStateHandle: SavedStateHandle,
    private val tagDao: TagDao,
    private val imageTagDao: ImageTagDao,
    private val imageDao: ImageDao,
    private val personDao: PersonDao,
    private val faceRecognitionRepository: FaceRecognitionRepository
) : ViewModel() {

    // Album parameters from navigation
    private val albumType: String = savedStateHandle["albumType"] ?: "tag"
    private val albumId: String = savedStateHandle["albumId"] ?: ""

    // UI state
    private val _uiState = MutableStateFlow<AlbumUiState>(AlbumUiState.Loading)
    val uiState: StateFlow<AlbumUiState> = _uiState.asStateFlow()

    // Search query within album
    private val _searchQuery = MutableStateFlow("")
    val searchQuery: StateFlow<String> = _searchQuery.asStateFlow()

    // Date range filter
    private val _dateRange = MutableStateFlow(DateRange.ALL_TIME)
    val dateRange: StateFlow<DateRange> = _dateRange.asStateFlow()

    init {
        loadAlbumData()
    }

    /**
     * Load album data based on type
     */
    private fun loadAlbumData() {
        viewModelScope.launch {
            try {
                _uiState.value = AlbumUiState.Loading

                when (albumType) {
                    "tag" -> loadTagAlbum()
                    "person" -> loadPersonAlbum()
                    "time" -> loadTimeAlbum()
                    else -> _uiState.value = AlbumUiState.Error("Unknown album type")
                }

            } catch (e: Exception) {
                _uiState.value = AlbumUiState.Error(e.message ?: "Failed to load album")
            }
        }
    }

    private suspend fun loadTagAlbum() {
        val tag = tagDao.getByValue(albumId)
        if (tag == null) {
            _uiState.value = AlbumUiState.Error("Tag not found")
            return
        }

        combine(
            _searchQuery,
            _dateRange
        ) { query: String, dateRange: DateRange ->
            Pair(query, dateRange)
        }.collectLatest { (query, dateRange) ->
            val imageIds = imageTagDao.findImagesByTag(tag.tagId, 0.5f)
            val images = imageDao.getImagesByIds(imageIds)

            val filteredImages = images
                .filter { isInDateRange(it.capturedAt, dateRange) }
                .filter {
                    query.isBlank() || containsQuery(it, query)
                }

            val imagesWithFaces = filteredImages.map { image ->
                val tagsWithPersons = faceRecognitionRepository.getFaceTagsWithPersons(image.imageId)
                AlbumPhoto(
                    image = image,
                    faceTags = tagsWithPersons.map { it.first },
                    persons = tagsWithPersons.map { it.second }
                )
            }

            val uniquePersons = imagesWithFaces
                .flatMap { it.persons }
                .distinctBy { it.id }

            _uiState.value = AlbumUiState.Success(
                albumName = tag.value.replace("_", " ").replaceFirstChar { it.uppercase() },
                albumType = "Tag",
                photos = imagesWithFaces,
                personCount = uniquePersons.size,
                totalFaces = imagesWithFaces.sumOf { it.faceTags.size }
            )
        }
    }

    private suspend fun loadPersonAlbum() {
        val person = personDao.getPersonById(albumId)
        if (person == null) {
            _uiState.value = AlbumUiState.Error("Person not found")
            return
        }

        combine(
            _searchQuery,
            _dateRange
        ) { query: String, dateRange: DateRange ->
            Pair(query, dateRange)
        }.collectLatest { (query, dateRange) ->
            val images = faceRecognitionRepository.getImagesForPerson(albumId)

            val filteredImages = images
                .filter { isInDateRange(it.capturedAt, dateRange) }
                .filter {
                    query.isBlank() || containsQuery(it, query)
                }

            val imagesWithFaces = filteredImages.map { image ->
                val tagsWithPersons = faceRecognitionRepository.getFaceTagsWithPersons(image.imageId)
                AlbumPhoto(
                    image = image,
                    faceTags = tagsWithPersons.map { it.first },
                    persons = tagsWithPersons.map { it.second }
                )
            }

            _uiState.value = AlbumUiState.Success(
                albumName = person.name,
                albumType = "Person",
                photos = imagesWithFaces,
                personCount = 1,
                totalFaces = imagesWithFaces.sumOf { it.faceTags.size }
            )
        }
    }

    private suspend fun loadTimeAlbum() {
        // Time-based albums (Today, This Week, etc)
        val (startTime, endTime, albumName) = when (albumId) {
            "today" -> Triple(getStartOfDay(), System.currentTimeMillis(), "Today")
            "week" -> Triple(getStartOfWeek(), System.currentTimeMillis(), "This Week")
            "month" -> Triple(getStartOfMonth(), System.currentTimeMillis(), "This Month")
            "year" -> Triple(getStartOfYear(), System.currentTimeMillis(), "This Year")
            else -> {
                _uiState.value = AlbumUiState.Error("Unknown time range")
                return
            }
        }

        combine(
            _searchQuery,
            _dateRange
        ) { query: String, _: DateRange ->
            query
        }.collectLatest { query ->
            val images = imageDao.getImagesInRange(startTime, endTime)

            val filteredImages = images.filter {
                query.isBlank() || containsQuery(it, query)
            }

            val imagesWithFaces = filteredImages.map { image ->
                val tagsWithPersons = faceRecognitionRepository.getFaceTagsWithPersons(image.imageId)
                AlbumPhoto(
                    image = image,
                    faceTags = tagsWithPersons.map { it.first },
                    persons = tagsWithPersons.map { it.second }
                )
            }

            val uniquePersons = imagesWithFaces
                .flatMap { it.persons }
                .distinctBy { it.id }

            _uiState.value = AlbumUiState.Success(
                albumName = albumName,
                albumType = "Time",
                photos = imagesWithFaces,
                personCount = uniquePersons.size,
                totalFaces = imagesWithFaces.sumOf { it.faceTags.size }
            )
        }
    }

    fun setSearchQuery(query: String) {
        _searchQuery.value = query
    }

    fun setDateRange(range: DateRange) {
        _dateRange.value = range
    }

    private fun isInDateRange(timestamp: Long, range: DateRange): Boolean {
        return when (range) {
            DateRange.ALL_TIME -> true
            DateRange.TODAY -> isToday(timestamp)
            DateRange.THIS_WEEK -> isThisWeek(timestamp)
            DateRange.THIS_MONTH -> isThisMonth(timestamp)
            DateRange.THIS_YEAR -> isThisYear(timestamp)
        }
    }

    private fun containsQuery(image: ImageEntity, query: String): Boolean {
        // Could expand to search by person names, tags, etc.
        return true
    }

    private fun isToday(timestamp: Long): Boolean {
        val today = Calendar.getInstance()
        val date = Calendar.getInstance().apply { timeInMillis = timestamp }
        return today.get(Calendar.YEAR) == date.get(Calendar.YEAR) &&
                today.get(Calendar.DAY_OF_YEAR) == date.get(Calendar.DAY_OF_YEAR)
    }

    private fun isThisWeek(timestamp: Long): Boolean {
        val today = Calendar.getInstance()
        val date = Calendar.getInstance().apply { timeInMillis = timestamp }
        return today.get(Calendar.YEAR) == date.get(Calendar.YEAR) &&
                today.get(Calendar.WEEK_OF_YEAR) == date.get(Calendar.WEEK_OF_YEAR)
    }

    private fun isThisMonth(timestamp: Long): Boolean {
        val today = Calendar.getInstance()
        val date = Calendar.getInstance().apply { timeInMillis = timestamp }
        return today.get(Calendar.YEAR) == date.get(Calendar.YEAR) &&
                today.get(Calendar.MONTH) == date.get(Calendar.MONTH)
    }

    private fun isThisYear(timestamp: Long): Boolean {
        val today = Calendar.getInstance()
        val date = Calendar.getInstance().apply { timeInMillis = timestamp }
        return today.get(Calendar.YEAR) == date.get(Calendar.YEAR)
    }

    private fun getStartOfDay(): Long {
        return Calendar.getInstance().apply {
            set(Calendar.HOUR_OF_DAY, 0)
            set(Calendar.MINUTE, 0)
            set(Calendar.SECOND, 0)
            set(Calendar.MILLISECOND, 0)
        }.timeInMillis
    }

    private fun getStartOfWeek(): Long {
        return Calendar.getInstance().apply {
            set(Calendar.DAY_OF_WEEK, firstDayOfWeek)
            set(Calendar.HOUR_OF_DAY, 0)
            set(Calendar.MINUTE, 0)
            set(Calendar.SECOND, 0)
            set(Calendar.MILLISECOND, 0)
        }.timeInMillis
    }

    private fun getStartOfMonth(): Long {
        return Calendar.getInstance().apply {
            set(Calendar.DAY_OF_MONTH, 1)
            set(Calendar.HOUR_OF_DAY, 0)
            set(Calendar.MINUTE, 0)
            set(Calendar.SECOND, 0)
            set(Calendar.MILLISECOND, 0)
        }.timeInMillis
    }

    private fun getStartOfYear(): Long {
        return Calendar.getInstance().apply {
            set(Calendar.DAY_OF_YEAR, 1)
            set(Calendar.HOUR_OF_DAY, 0)
            set(Calendar.MINUTE, 0)
            set(Calendar.SECOND, 0)
            set(Calendar.MILLISECOND, 0)
        }.timeInMillis
    }
}

sealed class AlbumUiState {
    object Loading : AlbumUiState()
    data class Success(
        val albumName: String,
        val albumType: String,
        val photos: List<AlbumPhoto>,
        val personCount: Int,
        val totalFaces: Int
    ) : AlbumUiState()
    data class Error(val message: String) : AlbumUiState()
}

data class AlbumPhoto(
    val image: ImageEntity,
    val faceTags: List<PhotoFaceTagEntity>,
    val persons: List<PersonEntity>
)