package com.placeholder.sherpai2.data.repository

import com.placeholder.sherpai2.data.local.dao.CollectionDao
import com.placeholder.sherpai2.data.local.dao.ImageAggregateDao
import com.placeholder.sherpai2.data.local.entity.*
import com.placeholder.sherpai2.data.local.model.CollectionWithDetails
import com.placeholder.sherpai2.ui.search.DateRange
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import javax.inject.Inject
import javax.inject.Singleton

/**
 * CollectionRepository - Business logic for collections
 *
 * Handles:
 * - Creating smart/static collections
 * - Evaluating smart collection filters
 * - Managing photos in collections
 * - Export functionality
 */
@Singleton
class CollectionRepository @Inject constructor(
    private val collectionDao: CollectionDao,
    private val imageAggregateDao: ImageAggregateDao
) {

    // ==========================================
    // COLLECTION OPERATIONS
    // ==========================================

    suspend fun createSmartCollection(
        name: String,
        description: String?,
        includedPeople: Set<String>,
        excludedPeople: Set<String>,
        includedTags: Set<String>,
        excludedTags: Set<String>,
        dateRange: DateRange
    ): String {
        // Create collection
        val collection = CollectionEntity.createSmart(name, description)
        collectionDao.insert(collection)

        // Save filters
        val filters = mutableListOf<CollectionFilterEntity>()

        includedPeople.forEach {
            filters.add(
                CollectionFilterEntity.create(
                    collection.collectionId,
                    "PERSON_INCLUDE",
                    it
                )
            )
        }

        excludedPeople.forEach {
            filters.add(
                CollectionFilterEntity.create(
                    collection.collectionId,
                    "PERSON_EXCLUDE",
                    it
                )
            )
        }

        includedTags.forEach {
            filters.add(
                CollectionFilterEntity.create(
                    collection.collectionId,
                    "TAG_INCLUDE",
                    it
                )
            )
        }

        excludedTags.forEach {
            filters.add(
                CollectionFilterEntity.create(
                    collection.collectionId,
                    "TAG_EXCLUDE",
                    it
                )
            )
        }

        if (dateRange != DateRange.ALL_TIME) {
            filters.add(
                CollectionFilterEntity.create(
                    collection.collectionId,
                    "DATE_RANGE",
                    dateRange.name
                )
            )
        }

        if (filters.isNotEmpty()) {
            collectionDao.insertFilters(filters)
        }

        // Evaluate and populate
        evaluateSmartCollection(collection.collectionId)

        return collection.collectionId
    }

    suspend fun createStaticCollection(
        name: String,
        description: String?,
        imageIds: List<String>
    ): String {
        val collection = CollectionEntity.createStatic(name, description, imageIds.size)
        collectionDao.insert(collection)

        // Add images
        val now = System.currentTimeMillis()
        val collectionImages = imageIds.mapIndexed { index, imageId ->
            CollectionImageEntity(
                collectionId = collection.collectionId,
                imageId = imageId,
                addedAt = now,
                sortOrder = index
            )
        }

        collectionDao.addImages(collectionImages)
        collectionDao.updatePhotoCount(collection.collectionId, now)

        // Set cover image to first image
        if (imageIds.isNotEmpty()) {
            val firstImage = imageAggregateDao.observeAllImagesWithEverything()
                .first()
                .find { it.image.imageId == imageIds.first() }

            if (firstImage != null) {
                collectionDao.updateCoverImage(collection.collectionId, firstImage.image.imageUri, now)
            }
        }

        return collection.collectionId
    }

    suspend fun deleteCollection(collectionId: String) {
        collectionDao.deleteById(collectionId)
    }

    fun getAllCollections(): Flow<List<CollectionEntity>> {
        return collectionDao.getAllCollections()
    }

    fun getCollection(collectionId: String): Flow<CollectionEntity?> {
        return collectionDao.getByIdFlow(collectionId)
    }

    fun getCollectionWithDetails(collectionId: String): Flow<CollectionWithDetails?> {
        return collectionDao.getCollectionWithDetails(collectionId)
    }

    // ==========================================
    // IMAGE MANAGEMENT
    // ==========================================

    suspend fun addImageToCollection(collectionId: String, imageId: String) {
        val now = System.currentTimeMillis()
        val count = collectionDao.getPhotoCount(collectionId)

        collectionDao.addImage(
            CollectionImageEntity(
                collectionId = collectionId,
                imageId = imageId,
                addedAt = now,
                sortOrder = count
            )
        )

        collectionDao.updatePhotoCount(collectionId, now)

        // Update cover image if this is the first photo
        if (count == 0) {
            val images = collectionDao.getPreviewImages(collectionId)
            if (images.isNotEmpty()) {
                collectionDao.updateCoverImage(collectionId, images.first().imageUri, now)
            }
        }
    }

    suspend fun removeImageFromCollection(collectionId: String, imageId: String) {
        collectionDao.removeImage(collectionId, imageId)
        collectionDao.updatePhotoCount(collectionId, System.currentTimeMillis())
    }

    suspend fun toggleFavorite(imageId: String) {
        val favCollection = collectionDao.getFavoriteCollection()
            ?: run {
                // Create favorites collection if it doesn't exist
                val fav = CollectionEntity.createFavorite()
                collectionDao.insert(fav)
                fav
            }

        val isFavorite = collectionDao.containsImage(favCollection.collectionId, imageId)

        if (isFavorite) {
            removeImageFromCollection(favCollection.collectionId, imageId)
        } else {
            addImageToCollection(favCollection.collectionId, imageId)
        }
    }

    suspend fun isFavorite(imageId: String): Boolean {
        val favCollection = collectionDao.getFavoriteCollection() ?: return false
        return collectionDao.containsImage(favCollection.collectionId, imageId)
    }

    fun getImagesInCollection(collectionId: String): Flow<List<ImageEntity>> {
        return collectionDao.getImagesInCollection(collectionId)
    }

    // ==========================================
    // SMART COLLECTION EVALUATION
    // ==========================================

    /**
     * Re-evaluate a SMART collection's filters and update its images
     */
    suspend fun evaluateSmartCollection(collectionId: String) {
        val collection = collectionDao.getById(collectionId) ?: return
        if (collection.type != "SMART") return

        val filters = collectionDao.getFilters(collectionId)
        if (filters.isEmpty()) return

        // Get all images
        val allImages = imageAggregateDao.observeAllImagesWithEverything().first()

        // Parse filters
        val includedPeople = filters
            .filter { it.filterType == "PERSON_INCLUDE" }
            .map { it.filterValue }
            .toSet()

        val excludedPeople = filters
            .filter { it.filterType == "PERSON_EXCLUDE" }
            .map { it.filterValue }
            .toSet()

        val includedTags = filters
            .filter { it.filterType == "TAG_INCLUDE" }
            .map { it.filterValue }
            .toSet()

        val excludedTags = filters
            .filter { it.filterType == "TAG_EXCLUDE" }
            .map { it.filterValue }
            .toSet()

        // Filter images (same logic as SearchViewModel)
        val matchingImages = allImages.filter { imageWithEverything ->
            // TODO: Apply same Boolean logic as SearchViewModel
            // For now, simple tag matching
            val imageTags = imageWithEverything.tags.map { it.value }.toSet()

            val hasIncludedTags = includedTags.isEmpty() || includedTags.all { it in imageTags }
            val hasNoExcludedTags = excludedTags.isEmpty() || excludedTags.none { it in imageTags }

            hasIncludedTags && hasNoExcludedTags
        }.map { it.image.imageId }

        // Update collection
        collectionDao.clearAllImages(collectionId)

        val now = System.currentTimeMillis()
        val collectionImages = matchingImages.mapIndexed { index, imageId ->
            CollectionImageEntity(
                collectionId = collectionId,
                imageId = imageId,
                addedAt = now,
                sortOrder = index
            )
        }

        if (collectionImages.isNotEmpty()) {
            collectionDao.addImages(collectionImages)

            // Set cover image to first image
            val firstImageId = matchingImages.first()
            val firstImage = allImages.find { it.image.imageId == firstImageId }
            if (firstImage != null) {
                collectionDao.updateCoverImage(collectionId, firstImage.image.imageUri, now)
            }
        }

        collectionDao.updatePhotoCount(collectionId, now)
    }

    /**
     * Re-evaluate all SMART collections
     */
    suspend fun evaluateAllSmartCollections() {
        val collections = collectionDao.getCollectionsByType("SMART").first()
        collections.forEach { collection ->
            evaluateSmartCollection(collection.collectionId)
        }
    }

    // ==========================================
    // UPDATES
    // ==========================================

    suspend fun updateCollectionDetails(
        collectionId: String,
        name: String,
        description: String?
    ) {
        collectionDao.updateDetails(collectionId, name, description, System.currentTimeMillis())
    }

    suspend fun togglePinned(collectionId: String) {
        val collection = collectionDao.getById(collectionId) ?: return
        collectionDao.updatePinned(
            collectionId,
            !collection.isPinned,
            System.currentTimeMillis()
        )
    }
}