package com.atridad.openclimb.ui.viewmodel

import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.atridad.openclimb.data.model.*
import com.atridad.openclimb.data.repository.ClimbRepository
import com.atridad.openclimb.service.SessionTrackingService
import com.atridad.openclimb.utils.ImageUtils
import com.atridad.openclimb.utils.SessionShareUtils
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File

class ClimbViewModel(
    private val repository: ClimbRepository
) : ViewModel() {
    
    // UI State flows
    private val _uiState = MutableStateFlow(ClimbUiState())
    val uiState: StateFlow<ClimbUiState> = _uiState.asStateFlow()
    
    // Data flows
    val gyms = repository.getAllGyms().stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(),
        initialValue = emptyList()
    )
    
    val problems = repository.getAllProblems().stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(),
        initialValue = emptyList()
    )
    
    val sessions = repository.getAllSessions().stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(),
        initialValue = emptyList()
    )
    
    val activeSession = repository.getActiveSessionFlow().stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(),
        initialValue = null
    )
    
    val attempts = repository.getAllAttempts().stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(),
        initialValue = emptyList()
    )
    

    
    // Gym operations
    fun addGym(gym: Gym) {
        viewModelScope.launch {
            repository.insertGym(gym)
        }
    }
    
    fun updateGym(gym: Gym) {
        viewModelScope.launch {
            repository.updateGym(gym)
        }
    }
    
    fun deleteGym(gym: Gym) {
        viewModelScope.launch {
            repository.deleteGym(gym)
        }
    }
    
    fun getGymById(id: String): Flow<Gym?> = flow {
        emit(repository.getGymById(id))
    }
    
    // Problem operations
    fun addProblem(problem: Problem) {
        viewModelScope.launch {
            repository.insertProblem(problem)
        }
    }
    
    fun updateProblem(problem: Problem) {
        viewModelScope.launch {
            repository.updateProblem(problem)
        }
    }
    
    fun deleteProblem(problem: Problem, context: Context) {
        viewModelScope.launch {
            // Delete associated images
            problem.imagePaths.forEach { imagePath ->
                ImageUtils.deleteImage(context, imagePath)
            }
            
            repository.deleteProblem(problem)
            
            // Clean up any remaining orphaned images
            cleanupOrphanedImages(context)
        }
    }
    
    private suspend fun cleanupOrphanedImages(context: Context) {
        val allProblems = repository.getAllProblems().first()
        val referencedImagePaths = allProblems.flatMap { it.imagePaths }.toSet()
        ImageUtils.cleanupOrphanedImages(context, referencedImagePaths)
    }
    
    fun getProblemById(id: String): Flow<Problem?> = flow {
        emit(repository.getProblemById(id))
    }
    
    fun getProblemsByGym(gymId: String): Flow<List<Problem>> = 
        repository.getProblemsByGym(gymId)
    
    // Session operations
    fun addSession(session: ClimbSession) {
        viewModelScope.launch {
            repository.insertSession(session)
        }
    }
    
    fun updateSession(session: ClimbSession) {
        viewModelScope.launch {
            repository.updateSession(session)
        }
    }
    
    fun deleteSession(session: ClimbSession) {
        viewModelScope.launch {
            repository.deleteSession(session)
        }
    }
    
    fun getSessionById(id: String): Flow<ClimbSession?> = flow {
        emit(repository.getSessionById(id))
    }
    
    fun getSessionsByGym(gymId: String): Flow<List<ClimbSession>> = 
        repository.getSessionsByGym(gymId)
        
    // Active session management
    fun startSession(context: Context, gymId: String, notes: String? = null) {
        viewModelScope.launch {
            val existingActive = repository.getActiveSession()
            if (existingActive != null) {
                _uiState.value = _uiState.value.copy(
                    error = "There's already an active session. Please end it first."
                )
                return@launch
            }
            
            val newSession = ClimbSession.create(gymId = gymId, notes = notes)
            repository.insertSession(newSession)
            
            // Start the tracking service
            val serviceIntent = SessionTrackingService.createStartIntent(context, newSession.id)
            context.startForegroundService(serviceIntent)
            
            _uiState.value = _uiState.value.copy(
                message = "Session started successfully!"
            )
        }
    }
    
    fun endSession(context: Context, sessionId: String) {
        viewModelScope.launch {
            val session = repository.getSessionById(sessionId)
            if (session != null && session.status == SessionStatus.ACTIVE) {
                val completedSession = with(ClimbSession) { session.complete() }
                repository.updateSession(completedSession)
                
                // Stop the tracking service
                val serviceIntent = SessionTrackingService.createStopIntent(context)
                context.startService(serviceIntent)
                
                _uiState.value = _uiState.value.copy(
                    message = "Session completed!"
                )
            }
        }
    }
    
    fun pauseSession(sessionId: String) {
        viewModelScope.launch {
            val session = repository.getSessionById(sessionId)
            if (session != null && session.status == SessionStatus.ACTIVE) {
                val pausedSession = session.copy(
                    status = SessionStatus.PAUSED,
                    updatedAt = java.time.LocalDateTime.now().toString()
                )
                repository.updateSession(pausedSession)
            }
        }
    }
    
    fun resumeSession(sessionId: String) {
        viewModelScope.launch {
            val session = repository.getSessionById(sessionId)
            if (session != null && session.status == SessionStatus.PAUSED) {
                val resumedSession = session.copy(
                    status = SessionStatus.ACTIVE,
                    updatedAt = java.time.LocalDateTime.now().toString()
                )
                repository.updateSession(resumedSession)
            }
        }
    }
    
    // Attempt operations
    fun addAttempt(attempt: Attempt) {
        viewModelScope.launch {
            repository.insertAttempt(attempt)
        }
    }
    
    fun updateAttempt(attempt: Attempt) {
        viewModelScope.launch {
            repository.updateAttempt(attempt)
        }
    }
    
    fun deleteAttempt(attempt: Attempt) {
        viewModelScope.launch {
            repository.deleteAttempt(attempt)
        }
    }
    
    fun getAttemptsBySession(sessionId: String): Flow<List<Attempt>> = 
        repository.getAttemptsBySession(sessionId)
    
    fun getAttemptsByProblem(problemId: String): Flow<List<Attempt>> = 
        repository.getAttemptsByProblem(problemId)
    

    
    // Analytics operations
    // fun getProblemProgress(problemId: String): Flow<ProblemProgress?> = 
    //     repository.getProblemProgress(problemId)
    
    // fun getSessionSummary(sessionId: String): Flow<SessionSummary?> = 
    //     repository.getSessionSummary(sessionId)
    
    // Export operations
    fun exportData(context: Context, directory: File? = null) {
        viewModelScope.launch {
            try {
                _uiState.value = _uiState.value.copy(isLoading = true)
                val exportFile = repository.exportAllDataToJson(directory)
                _uiState.value = _uiState.value.copy(
                    isLoading = false,
                    message = "Data exported to: ${exportFile.absolutePath}"
                )
            } catch (e: Exception) {
                _uiState.value = _uiState.value.copy(
                    isLoading = false,
                    error = "Export failed: ${e.message}"
                )
            }
        }
    }
    
    fun exportDataToUri(context: Context, uri: android.net.Uri) {
        viewModelScope.launch {
            try {
                _uiState.value = _uiState.value.copy(isLoading = true)
                repository.exportAllDataToUri(context, uri)
                _uiState.value = _uiState.value.copy(
                    isLoading = false,
                    message = "Data exported successfully"
                )
            } catch (e: Exception) {
                _uiState.value = _uiState.value.copy(
                    isLoading = false,
                    error = "Export failed: ${e.message}"
                )
            }
        }
    }
    
    // ZIP Export operations with images
    fun exportDataToZip(context: Context, directory: File? = null) {
        viewModelScope.launch {
            try {
                _uiState.value = _uiState.value.copy(isLoading = true)
                val exportFile = repository.exportAllDataToZip(directory)
                _uiState.value = _uiState.value.copy(
                    isLoading = false,
                    message = "Data with images exported to: ${exportFile.absolutePath}"
                )
            } catch (e: Exception) {
                _uiState.value = _uiState.value.copy(
                    isLoading = false,
                    error = "Export failed: ${e.message}"
                )
            }
        }
    }
    
    fun exportDataToZipUri(context: Context, uri: android.net.Uri) {
        viewModelScope.launch {
            try {
                _uiState.value = _uiState.value.copy(isLoading = true)
                repository.exportAllDataToZipUri(context, uri)
                _uiState.value = _uiState.value.copy(
                    isLoading = false,
                    message = "Data with images exported successfully"
                )
            } catch (e: Exception) {
                _uiState.value = _uiState.value.copy(
                    isLoading = false,
                    error = "Export failed: ${e.message}"
                )
            }
        }
    }
    
    fun importData(file: File) {
        viewModelScope.launch {
            try {
                _uiState.value = _uiState.value.copy(isLoading = true)
                
                // Check if it's a ZIP file or JSON file
                if (file.name.lowercase().endsWith(".zip")) {
                    repository.importDataFromZip(file)
                } else {
                    repository.importDataFromJson(file)
                }
                
                _uiState.value = _uiState.value.copy(
                    isLoading = false,
                    message = "Data imported successfully from ${file.name}"
                )
            } catch (e: Exception) {
                _uiState.value = _uiState.value.copy(
                    isLoading = false,
                    error = "Import failed: ${e.message}"
                )
            }
        }
    }
    
    // UI state operations
    fun clearMessage() {
        _uiState.value = _uiState.value.copy(message = null)
    }
    
    fun clearError() {
        _uiState.value = _uiState.value.copy(error = null)
    }
    
    fun setError(message: String) {
        _uiState.value = _uiState.value.copy(error = message)
    }
    
    // Search operations
    fun searchGyms(query: String): Flow<List<Gym>> = repository.searchGyms(query)
    fun searchProblems(query: String): Flow<List<Problem>> = repository.searchProblems(query)
    
    // Share operations
    suspend fun generateSessionShareCard(
        context: Context,
        sessionId: String
    ): File? = withContext(Dispatchers.IO) {
        try {
            val session = repository.getSessionById(sessionId) ?: return@withContext null
            val attempts = repository.getAttemptsBySession(sessionId).first()
            val problems = repository.getAllProblems().first().filter { problem ->
                attempts.any { it.problemId == problem.id }
            }
            val gym = repository.getGymById(session.gymId) ?: return@withContext null
            
            val stats = SessionShareUtils.calculateSessionStats(session, attempts, problems)
            SessionShareUtils.generateShareCard(context, session, gym, stats)
        } catch (e: Exception) {
            _uiState.value = _uiState.value.copy(error = "Failed to generate share card: ${e.message}")
            null
        }
    }
    
    fun shareSessionCard(context: Context, imageFile: File) {
        SessionShareUtils.shareSessionCard(context, imageFile)
    }
}

data class ClimbUiState(
    val isLoading: Boolean = false,
    val message: String? = null,
    val error: String? = null
)
