package com.placeholder.sherpai2.ui.discover

import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.work.*
import com.placeholder.sherpai2.data.local.dao.FaceCacheDao
import com.placeholder.sherpai2.data.local.entity.FeedbackType
import com.placeholder.sherpai2.domain.clustering.*
import com.placeholder.sherpai2.domain.training.ClusterTrainingService
import com.placeholder.sherpai2.domain.validation.ValidationScanResult
import com.placeholder.sherpai2.domain.validation.ValidationScanService
import com.placeholder.sherpai2.workers.CachePopulationWorker
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class DiscoverPeopleViewModel @Inject constructor(
    @ApplicationContext private val context: Context,
    private val clusteringService: FaceClusteringService,
    private val trainingService: ClusterTrainingService,
    private val validationService: ValidationScanService,
    private val refinementService: ClusterRefinementService,
    private val faceCacheDao: FaceCacheDao
) : ViewModel() {

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

    private val namedClusterIds = mutableSetOf<Int>()
    private var currentIterationCount = 0

    // NEW: Store settings for use after cache population
    private var lastUsedSettings: DiscoverySettings = DiscoverySettings.DEFAULT

    private val workManager = WorkManager.getInstance(context)
    private var cacheWorkRequestId: java.util.UUID? = null

    /**
     * ENHANCED: Check cache before starting Discovery (with settings support)
     */
    fun startDiscovery(settings: DiscoverySettings = DiscoverySettings.DEFAULT) {
        lastUsedSettings = settings  // Store for later use

        // LOG SETTINGS
        android.util.Log.d("DiscoverVM", "═══════════════════════════════════════")
        android.util.Log.d("DiscoverVM", "🎛️  DISCOVERY SETTINGS")
        android.util.Log.d("DiscoverVM", "═══════════════════════════════════════")
        android.util.Log.d("DiscoverVM", "Min Face Size:  ${settings.minFaceSize} (${(settings.minFaceSize * 100).toInt()}%)")
        android.util.Log.d("DiscoverVM", "Min Quality:    ${settings.minQuality} (${(settings.minQuality * 100).toInt()}%)")
        android.util.Log.d("DiscoverVM", "Epsilon:        ${settings.epsilon}")
        android.util.Log.d("DiscoverVM", "Is Default:     ${settings == DiscoverySettings.DEFAULT}")
        android.util.Log.d("DiscoverVM", "═══════════════════════════════════════")
        viewModelScope.launch {
            try {
                namedClusterIds.clear()
                currentIterationCount = 0

                // Check cache status
                val cacheStats = faceCacheDao.getCacheStats()

                android.util.Log.d("DiscoverVM", "Cache check: totalFaces=${cacheStats.totalFaces}")

                if (cacheStats.totalFaces == 0) {
                    // Cache empty - need to build it first
                    android.util.Log.d("DiscoverVM", "Cache empty, starting cache population")

                    _uiState.value = DiscoverUiState.BuildingCache(
                        progress = 0,
                        total = 100,
                        message = "First-time setup: Building face cache...\n\nThis is a one-time process that will take 5-10 minutes."
                    )

                    startCachePopulation()
                } else {
                    android.util.Log.d("DiscoverVM", "Cache exists (${cacheStats.totalFaces} faces), proceeding to Discovery")

                    // Cache exists - proceed to Discovery
                    _uiState.value = DiscoverUiState.Clustering(0, 100, "Starting discovery...")
                    executeDiscovery()
                }
            } catch (e: Exception) {
                android.util.Log.e("DiscoverVM", "Error checking cache", e)
                _uiState.value = DiscoverUiState.Error(
                    "Failed to check cache: ${e.message}"
                )
            }
        }
    }

    /**
     * Start cache population worker
     */
    private fun startCachePopulation() {
        viewModelScope.launch {
            android.util.Log.d("DiscoverVM", "Enqueuing CachePopulationWorker")

            val workRequest = OneTimeWorkRequestBuilder<CachePopulationWorker>()
                .setConstraints(
                    Constraints.Builder()
                        .setRequiresCharging(false)
                        .setRequiresBatteryNotLow(false)
                        .build()
                )
                .build()

            cacheWorkRequestId = workRequest.id

            // Enqueue work
            workManager.enqueueUniqueWork(
                CachePopulationWorker.WORK_NAME,
                ExistingWorkPolicy.REPLACE,
                workRequest
            )

            // Observe progress
            workManager.getWorkInfoByIdLiveData(workRequest.id).observeForever { workInfo ->
                android.util.Log.d("DiscoverVM", "Worker state: ${workInfo?.state}")

                when (workInfo?.state) {
                    WorkInfo.State.RUNNING -> {
                        val current = workInfo.progress.getInt(
                            CachePopulationWorker.KEY_PROGRESS_CURRENT,
                            0
                        )
                        val total = workInfo.progress.getInt(
                            CachePopulationWorker.KEY_PROGRESS_TOTAL,
                            100
                        )

                        _uiState.value = DiscoverUiState.BuildingCache(
                            progress = current,
                            total = total,
                            message = "Building face cache...\n\nAnalyzing $current of $total photos\n\nThis improves future Discovery performance by 95%!"
                        )
                    }

                    WorkInfo.State.SUCCEEDED -> {
                        val cachedCount = workInfo.outputData.getInt(
                            CachePopulationWorker.KEY_CACHED_COUNT,
                            0
                        )

                        android.util.Log.d("DiscoverVM", "Cache population complete: $cachedCount faces")

                        _uiState.value = DiscoverUiState.BuildingCache(
                            progress = 100,
                            total = 100,
                            message = "Cache complete! Found $cachedCount faces.\n\nStarting Discovery now..."
                        )

                        // Automatically start Discovery after cache is ready
                        viewModelScope.launch {
                            kotlinx.coroutines.delay(1000)
                            _uiState.value = DiscoverUiState.Clustering(0, 100, "Starting discovery...")
                            executeDiscovery()
                        }
                    }

                    WorkInfo.State.FAILED -> {
                        val error = workInfo.outputData.getString("error")
                        android.util.Log.e("DiscoverVM", "Cache population failed: $error")

                        _uiState.value = DiscoverUiState.Error(
                            "Cache building failed: ${error ?: "Unknown error"}\n\n" +
                                    "Discovery will use slower full-scan mode.\n\n" +
                                    "You can retry cache building later."
                        )
                    }

                    else -> {
                        // ENQUEUED, BLOCKED, CANCELLED
                    }
                }
            }
        }
    }

    /**
     * Execute the actual Discovery clustering (with settings support)
     */
    private suspend fun executeDiscovery() {
        try {
            // LOG WHICH PATH WE'RE TAKING
            android.util.Log.d("DiscoverVM", "═══════════════════════════════════════")
            android.util.Log.d("DiscoverVM", "🚀 EXECUTING DISCOVERY")
            android.util.Log.d("DiscoverVM", "═══════════════════════════════════════")

            // Use discoverPeopleWithSettings if settings are non-default
            val result = if (lastUsedSettings == DiscoverySettings.DEFAULT) {
                android.util.Log.d("DiscoverVM", "Using DEFAULT settings path")
                android.util.Log.d("DiscoverVM", "Calling: clusteringService.discoverPeople()")

                // Use regular method for default settings
                clusteringService.discoverPeople(
                    strategy = ClusteringStrategy.PREMIUM_SOLO_ONLY,
                    onProgress = { current: Int, total: Int, message: String ->
                        _uiState.value = DiscoverUiState.Clustering(current, total, message)
                    }
                )
            } else {
                android.util.Log.d("DiscoverVM", "Using CUSTOM settings path")
                android.util.Log.d("DiscoverVM", "Settings: minFaceSize=${lastUsedSettings.minFaceSize}, minQuality=${lastUsedSettings.minQuality}, epsilon=${lastUsedSettings.epsilon}")
                android.util.Log.d("DiscoverVM", "Calling: clusteringService.discoverPeopleWithSettings()")

                // Use settings-aware method
                clusteringService.discoverPeopleWithSettings(
                    settings = lastUsedSettings,
                    onProgress = { current: Int, total: Int, message: String ->
                        _uiState.value = DiscoverUiState.Clustering(current, total, message)
                    }
                )
            }

            android.util.Log.d("DiscoverVM", "Discovery complete: ${result.clusters.size} clusters found")
            android.util.Log.d("DiscoverVM", "═══════════════════════════════════════")

            if (result.errorMessage != null) {
                _uiState.value = DiscoverUiState.Error(result.errorMessage)
                return
            }

            if (result.clusters.isEmpty()) {
                _uiState.value = DiscoverUiState.NoPeopleFound(
                    result.errorMessage
                        ?: "No people clusters found.\n\nTry:\n• Adding more solo photos\n• Ensuring photos are clear\n• Having 6+ photos per person"
                )
            } else {
                _uiState.value = DiscoverUiState.NamingReady(result)
            }
        } catch (e: Exception) {
            android.util.Log.e("DiscoverVM", "Discovery failed", e)
            _uiState.value = DiscoverUiState.Error(e.message ?: "Failed to discover people")
        }
    }

    fun selectCluster(cluster: FaceCluster) {
        val currentState = _uiState.value
        if (currentState is DiscoverUiState.NamingReady) {
            _uiState.value = DiscoverUiState.NamingCluster(
                result = currentState.result,
                selectedCluster = cluster,
                suggestedSiblings = currentState.result.clusters.filter {
                    it.clusterId in cluster.potentialSiblings
                }
            )
        }
    }

    fun confirmClusterName(
        cluster: FaceCluster,
        name: String,
        dateOfBirth: Long?,
        isChild: Boolean,
        selectedSiblings: List<Int>
    ) {
        viewModelScope.launch {
            try {
                val currentState = _uiState.value
                if (currentState !is DiscoverUiState.NamingCluster) return@launch

                _uiState.value = DiscoverUiState.AnalyzingCluster

                _uiState.value = DiscoverUiState.Training(
                    stage = "Creating face model for $name...",
                    progress = 0,
                    total = cluster.faces.size
                )

                val personId = trainingService.trainFromCluster(
                    cluster = cluster,
                    name = name,
                    dateOfBirth = dateOfBirth,
                    isChild = isChild,
                    siblingClusterIds = selectedSiblings,
                    onProgress = { current: Int, total: Int, message: String ->
                        _uiState.value = DiscoverUiState.Training(message, current, total)
                    }
                )

                _uiState.value = DiscoverUiState.Training(
                    stage = "Running validation scan...",
                    progress = 0,
                    total = 100
                )

                val validationResult = validationService.performValidationScan(
                    personId = personId,
                    onProgress = { current: Int, total: Int ->
                        _uiState.value = DiscoverUiState.Training(
                            stage = "Validating model quality...",
                            progress = current,
                            total = total
                        )
                    }
                )

                _uiState.value = DiscoverUiState.ValidationPreview(
                    personId = personId,
                    personName = name,
                    cluster = cluster,
                    validationResult = validationResult
                )

            } catch (e: Exception) {
                _uiState.value = DiscoverUiState.Error(e.message ?: "Failed to create person")
            }
        }
    }

    fun submitFeedback(
        cluster: FaceCluster,
        feedbackMap: Map<String, FeedbackType>
    ) {
        viewModelScope.launch {
            try {
                val faceFeedbackMap = cluster.faces
                    .associateWith { face ->
                        feedbackMap[face.imageId] ?: FeedbackType.UNCERTAIN
                    }

                val originalConfidences = cluster.faces.associateWith { it.confidence }

                refinementService.storeFeedback(
                    cluster = cluster,
                    feedbackMap = faceFeedbackMap,
                    originalConfidences = originalConfidences
                )

                val recommendation = refinementService.shouldRefineCluster(cluster)

                if (recommendation.shouldRefine) {
                    _uiState.value = DiscoverUiState.RefinementNeeded(
                        cluster = cluster,
                        recommendation = recommendation,
                        currentIteration = currentIterationCount
                    )
                }
            } catch (e: Exception) {
                _uiState.value = DiscoverUiState.Error(
                    "Failed to process feedback: ${e.message}"
                )
            }
        }
    }

    fun requestRefinement(cluster: FaceCluster) {
        viewModelScope.launch {
            try {
                currentIterationCount++

                _uiState.value = DiscoverUiState.Refining(
                    iteration = currentIterationCount,
                    message = "Removing incorrect faces and re-clustering..."
                )

                val refinementResult = refinementService.refineCluster(
                    cluster = cluster,
                    iterationNumber = currentIterationCount
                )

                if (!refinementResult.success || refinementResult.refinedCluster == null) {
                    _uiState.value = DiscoverUiState.Error(
                        refinementResult.errorMessage
                            ?: "Failed to refine cluster. Please try manual training."
                    )
                    return@launch
                }

                val currentState = _uiState.value
                if (currentState is DiscoverUiState.RefinementNeeded) {
                    confirmClusterName(
                        cluster = refinementResult.refinedCluster,
                        name = currentState.cluster.representativeFaces.first().imageId,
                        dateOfBirth = null,
                        isChild = false,
                        selectedSiblings = emptyList()
                    )
                }

            } catch (e: Exception) {
                _uiState.value = DiscoverUiState.Error(
                    "Refinement failed: ${e.message}"
                )
            }
        }
    }

    fun approveValidationAndScan(personId: String, personName: String) {
        viewModelScope.launch {
            try {
                _uiState.value = DiscoverUiState.Complete(
                    message = "Successfully created model for \"$personName\"!\n\n" +
                            "Full library scan has been queued in the background.\n\n" +
                            "✅ ${currentIterationCount} refinement iterations completed"
                )
            } catch (e: Exception) {
                _uiState.value = DiscoverUiState.Error(e.message ?: "Failed to start library scan")
            }
        }
    }

    fun rejectValidationAndImprove() {
        _uiState.value = DiscoverUiState.Error(
            "Please add more training photos and try again.\n\n" +
                    "(Feature coming: ability to add photos to existing model)"
        )
    }

    fun cancelNaming() {
        val currentState = _uiState.value
        if (currentState is DiscoverUiState.NamingCluster) {
            _uiState.value = DiscoverUiState.NamingReady(result = currentState.result)
        }
    }

    fun reset() {
        cacheWorkRequestId?.let { workId ->
            workManager.cancelWorkById(workId)
        }

        _uiState.value = DiscoverUiState.Idle
        namedClusterIds.clear()
        currentIterationCount = 0
    }

    /**
     * Retry discovery (returns to idle state)
     */
    fun retryDiscovery() {
        _uiState.value = DiscoverUiState.Idle
    }

    /**
     * Accept validation results and finish
     */
    fun acceptValidationAndFinish() {
        _uiState.value = DiscoverUiState.Complete(
            "Person created successfully!"
        )
    }

    /**
     * Skip refinement and finish
     */
    fun skipRefinement() {
        _uiState.value = DiscoverUiState.Complete(
            "Person created successfully!"
        )
    }
}

/**
 * UI States - ENHANCED with BuildingCache state
 */
sealed class DiscoverUiState {
    object Idle : DiscoverUiState()

    data class BuildingCache(
        val progress: Int,
        val total: Int,
        val message: String
    ) : DiscoverUiState()

    data class Clustering(
        val progress: Int,
        val total: Int,
        val message: String
    ) : DiscoverUiState()

    data class NamingReady(
        val result: ClusteringResult
    ) : DiscoverUiState()

    data class NamingCluster(
        val result: ClusteringResult,
        val selectedCluster: FaceCluster,
        val suggestedSiblings: List<FaceCluster>
    ) : DiscoverUiState()

    object AnalyzingCluster : DiscoverUiState()

    data class Training(
        val stage: String,
        val progress: Int,
        val total: Int
    ) : DiscoverUiState()

    data class ValidationPreview(
        val personId: String,
        val personName: String,
        val cluster: FaceCluster,
        val validationResult: ValidationScanResult
    ) : DiscoverUiState()

    data class RefinementNeeded(
        val cluster: FaceCluster,
        val recommendation: RefinementRecommendation,
        val currentIteration: Int
    ) : DiscoverUiState()

    data class Refining(
        val iteration: Int,
        val message: String
    ) : DiscoverUiState()

    data class Complete(
        val message: String
    ) : DiscoverUiState()

    data class NoPeopleFound(
        val message: String
    ) : DiscoverUiState()

    data class Error(
        val message: String
    ) : DiscoverUiState()
}