package de.krisenvorrat.app.ui.settings

import android.content.Context
import android.net.Uri
import androidx.core.content.FileProvider
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import de.krisenvorrat.app.data.sync.WebSocketClient
import de.krisenvorrat.app.data.sync.WebSocketEvent
import de.krisenvorrat.app.domain.model.AgeGroup
import de.krisenvorrat.app.domain.model.AgeGroupEntry
import de.krisenvorrat.app.domain.model.SettingsKeys
import de.krisenvorrat.app.domain.model.defaultAgeGroups
import de.krisenvorrat.app.domain.model.parseAgeGroupsFromJson
import de.krisenvorrat.app.domain.model.toJson
import de.krisenvorrat.app.domain.repository.ImportExportRepository
import de.krisenvorrat.app.domain.repository.SettingsRepository
import de.krisenvorrat.app.domain.repository.SyncService
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import java.io.File
import java.time.Instant
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.util.Locale
import javax.inject.Inject

@HiltViewModel
internal class SettingsViewModel @Inject constructor(
    private val settingsRepository: SettingsRepository,
    private val importExportRepository: ImportExportRepository,
    private val syncService: SyncService,
    private val webSocketClient: WebSocketClient,
    @ApplicationContext private val context: Context
) : ViewModel() {

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

    init {
        loadSettings()
        observeWebSocketEvents()
    }

    private fun observeWebSocketEvents() {
        viewModelScope.launch {
            webSocketClient.events.collect { event ->
                when (event) {
                    is WebSocketEvent.FullSyncRequired -> pullSync(fullSync = true)
                    is WebSocketEvent.InventoryUpdated -> pullSync(fullSync = false)
                    is WebSocketEvent.ConnectionFailed -> {
                        _uiState.update { it.copy(syncStatus = SyncStatus.Error(event.message)) }
                    }
                    is WebSocketEvent.Connected -> {
                        _uiState.update { it.copy(syncStatus = SyncStatus.Idle) }
                    }
                    else -> {}
                }
            }
        }
    }

    private fun loadSettings() {
        viewModelScope.launch {
            try {
                val ageGroups = loadAgeGroupsWithMigration()
                val serverUrl = settingsRepository.getValue(KEY_SERVER_URL) ?: ""
                val authUsername = settingsRepository.getValue(KEY_AUTH_USERNAME) ?: ""
                val accessToken = settingsRepository.getValue(KEY_ACCESS_TOKEN) ?: ""
                val isLoggedIn = authUsername.isNotBlank() && accessToken.isNotBlank()
                val openAiApiKey = settingsRepository.getValue(KEY_OPENAI_API_KEY) ?: ""
                val lastSyncTimestamp = settingsRepository.getValue(KEY_SYNC_LAST_TIMESTAMP)

                _uiState.update {
                    it.copy(
                        ageGroups = ageGroups,
                        serverUrl = serverUrl,
                        isLoggedIn = isLoggedIn,
                        loggedInUsername = authUsername,
                        openAiApiKey = openAiApiKey,
                        lastSyncTime = lastSyncTimestamp?.let { ts -> formatTimestamp(ts) },
                        isLoading = false
                    )
                }

                if (isLoggedIn) {
                    webSocketClient.connect(serverUrl, accessToken)
                }
            } catch (e: Exception) {
                _uiState.update {
                    it.copy(
                        ageGroups = defaultAgeGroups(),
                        isLoading = false
                    )
                }
            }
        }
    }

    private suspend fun loadAgeGroupsWithMigration(): List<AgeGroupEntry> {
        val ageGroupsJsonValue = settingsRepository.getValue(KEY_AGE_GROUPS)
        if (ageGroupsJsonValue != null) {
            return parseAgeGroupsFromJson(ageGroupsJsonValue)
        }
        val legacyHouseholdSize = settingsRepository.getValue(KEY_HOUSEHOLD_SIZE)?.toIntOrNull()
        if (legacyHouseholdSize != null) {
            val legacyKcal = settingsRepository.getValue(KEY_DAILY_KCAL_PER_PERSON)?.toIntOrNull()
                ?: AgeGroup.ERWACHSENER.defaultKcal
            return defaultAgeGroups().map { entry ->
                if (entry.ageGroup == AgeGroup.ERWACHSENER) {
                    entry.copy(count = legacyHouseholdSize, kcalPerDay = legacyKcal)
                } else {
                    entry
                }
            }
        }
        return defaultAgeGroups()
    }

    fun onAgeGroupCountChanged(ageGroup: AgeGroup, count: String) {
        val parsed = count.toIntOrNull()?.takeIf { it >= 0 } ?: return
        _uiState.update { state ->
            state.copy(
                ageGroups = state.ageGroups.map { entry ->
                    if (entry.ageGroup == ageGroup) entry.copy(count = parsed) else entry
                },
                isSaved = false
            )
        }
    }

    fun onAgeGroupKcalChanged(ageGroup: AgeGroup, kcal: String) {
        val parsed = kcal.toIntOrNull()?.takeIf { it > 0 } ?: return
        _uiState.update { state ->
            state.copy(
                ageGroups = state.ageGroups.map { entry ->
                    if (entry.ageGroup == ageGroup) entry.copy(kcalPerDay = parsed) else entry
                },
                isSaved = false
            )
        }
    }

    fun onServerUrlChanged(value: String) {
        _uiState.update { it.copy(serverUrl = value, isSaved = false) }
    }

    fun onLoginUsernameChanged(value: String) {
        _uiState.update { it.copy(loginUsername = value, loginError = null) }
    }

    fun onLoginPasswordChanged(value: String) {
        _uiState.update { it.copy(loginPassword = value, loginError = null) }
    }

    fun login() {
        val serverUrl = _uiState.value.serverUrl.trim()
        val username = _uiState.value.loginUsername.trim()
        val password = _uiState.value.loginPassword
        if (serverUrl.isBlank() || username.isBlank() || password.isBlank()) {
            _uiState.update { it.copy(loginError = "Bitte Server-URL, Benutzername und Passwort eingeben") }
            return
        }
        viewModelScope.launch {
            _uiState.update { it.copy(isLoggingIn = true, loginError = null) }
            syncService.login(serverUrl, username, password).fold(
                onSuccess = {
                    val accessToken = settingsRepository.getValue(KEY_ACCESS_TOKEN) ?: ""
                    webSocketClient.connect(serverUrl, accessToken)
                    _uiState.update {
                        it.copy(
                            isLoggingIn = false,
                            isLoggedIn = true,
                            loggedInUsername = username,
                            loginUsername = "",
                            loginPassword = ""
                        )
                    }
                },
                onFailure = { e ->
                    _uiState.update {
                        it.copy(
                            isLoggingIn = false,
                            loginError = e.message ?: "Anmeldung fehlgeschlagen"
                        )
                    }
                }
            )
        }
    }

    fun logout() {
        viewModelScope.launch {
            syncService.logout()
            webSocketClient.disconnect()
            _uiState.update {
                it.copy(
                    isLoggedIn = false,
                    loggedInUsername = "",
                    syncStatus = SyncStatus.Idle
                )
            }
        }
    }

    fun onOpenAiApiKeyChanged(value: String) {
        _uiState.update { it.copy(openAiApiKey = value, isSaved = false) }
    }

    fun saveSettings() {
        viewModelScope.launch {
            try {
                settingsRepository.setValue(KEY_AGE_GROUPS, _uiState.value.ageGroups.toJson())
                settingsRepository.setValue(KEY_SERVER_URL, _uiState.value.serverUrl)
                settingsRepository.setValue(KEY_OPENAI_API_KEY, _uiState.value.openAiApiKey)

                _uiState.update { it.copy(isSaved = true) }
            } catch (e: Exception) {
                // Fehler beim Speichern – UI zeigt keinen Saved-Status
            }
        }
    }

    fun exportJson() {
        viewModelScope.launch {
            _uiState.update { it.copy(isExporting = true, exportError = null) }
            try {
                val json = importExportRepository.exportToJson()
                val cacheDir = File(context.cacheDir, "exports")
                cacheDir.mkdirs()
                val file = File(cacheDir, "krisenvorrat_export.json")
                file.writeText(json)
                val uri = FileProvider.getUriForFile(
                    context,
                    "${context.packageName}.fileprovider",
                    file
                )
                _uiState.update { it.copy(isExporting = false, shareContent = ShareContent.Json(uri)) }
            } catch (e: Exception) {
                _uiState.update { it.copy(isExporting = false, exportError = "Export fehlgeschlagen") }
            }
        }
    }

    fun exportMarkdown() {
        viewModelScope.launch {
            _uiState.update { it.copy(isExporting = true, exportError = null) }
            try {
                val markdown = importExportRepository.exportToMarkdown()
                _uiState.update { it.copy(isExporting = false, shareContent = ShareContent.Markdown(markdown)) }
            } catch (e: Exception) {
                _uiState.update { it.copy(isExporting = false, exportError = "Export fehlgeschlagen") }
            }
        }
    }

    fun onShareHandled() {
        _uiState.update { it.copy(shareContent = null) }
    }

    fun onExportErrorDismissed() {
        _uiState.update { it.copy(exportError = null) }
    }

    fun onImportFileSelected(uri: Uri) {
        _uiState.update { it.copy(pendingImportUri = uri) }
    }

    fun onImportConfirmed() {
        val uri = _uiState.value.pendingImportUri ?: return
        _uiState.update { it.copy(pendingImportUri = null, isImporting = true, importResult = null) }
        viewModelScope.launch {
            try {
                val json = context.contentResolver.openInputStream(uri)?.bufferedReader()?.use { it.readText() }
                if (json.isNullOrBlank()) {
                    _uiState.update { it.copy(isImporting = false, importResult = ImportResult.Error("Datei ist leer oder konnte nicht gelesen werden")) }
                    return@launch
                }
                val result = importExportRepository.importFromJson(json)
                result.fold(
                    onSuccess = {
                        loadSettings()
                        _uiState.update { it.copy(isImporting = false, importResult = ImportResult.Success) }
                    },
                    onFailure = { e ->
                        _uiState.update { it.copy(isImporting = false, importResult = ImportResult.Error(e.message ?: "Import fehlgeschlagen")) }
                    }
                )
            } catch (e: Exception) {
                _uiState.update { it.copy(isImporting = false, importResult = ImportResult.Error("Datei konnte nicht gelesen werden")) }
            }
        }
    }

    fun onImportDismissed() {
        _uiState.update { it.copy(pendingImportUri = null) }
    }

    fun onImportResultDismissed() {
        _uiState.update { it.copy(importResult = null) }
    }

    fun pushSync() {
        viewModelScope.launch {
            _uiState.update { it.copy(syncStatus = SyncStatus.Running) }
            try {
                val inventoryDto = importExportRepository.exportToInventoryDto()
                val result = syncService.uploadInventory(inventoryDto)
                result.fold(
                    onSuccess = {
                        val now = Instant.now().toEpochMilli().toString()
                        settingsRepository.setValue(KEY_SYNC_LAST_TIMESTAMP, now)
                        _uiState.update {
                            it.copy(
                                syncStatus = SyncStatus.Success,
                                lastSyncTime = formatTimestamp(now)
                            )
                        }
                    },
                    onFailure = { e ->
                        _uiState.update {
                            it.copy(syncStatus = SyncStatus.Error(e.message ?: "Push fehlgeschlagen"))
                        }
                    }
                )
            } catch (e: Exception) {
                _uiState.update {
                    it.copy(syncStatus = SyncStatus.Error(e.message ?: "Push fehlgeschlagen"))
                }
            }
        }
    }

    fun pullSync(fullSync: Boolean = false) {
        viewModelScope.launch {
            _uiState.update { it.copy(syncStatus = SyncStatus.Running) }
            try {
                val since = if (fullSync) null else settingsRepository.getValue(KEY_SYNC_LAST_TIMESTAMP)?.toLongOrNull()
                val result = syncService.downloadInventory(since)
                result.fold(
                    onSuccess = { inventoryDto ->
                        importExportRepository.importFromInventoryDto(inventoryDto).fold(
                            onSuccess = {
                                val now = Instant.now().toEpochMilli().toString()
                                settingsRepository.setValue(KEY_SYNC_LAST_TIMESTAMP, now)
                                loadSettings()
                                _uiState.update {
                                    it.copy(
                                        syncStatus = SyncStatus.Success,
                                        lastSyncTime = formatTimestamp(now)
                                    )
                                }
                            },
                            onFailure = { e ->
                                _uiState.update {
                                    it.copy(syncStatus = SyncStatus.Error(e.message ?: "Import fehlgeschlagen"))
                                }
                            }
                        )
                    },
                    onFailure = { e ->
                        _uiState.update {
                            it.copy(syncStatus = SyncStatus.Error(e.message ?: "Pull fehlgeschlagen"))
                        }
                    }
                )
            } catch (e: Exception) {
                _uiState.update {
                    it.copy(syncStatus = SyncStatus.Error(e.message ?: "Pull fehlgeschlagen"))
                }
            }
        }
    }

    fun onSyncStatusDismissed() {
        _uiState.update { it.copy(syncStatus = SyncStatus.Idle) }
    }

    private fun formatTimestamp(epochMillisStr: String): String? {
        val millis = epochMillisStr.toLongOrNull() ?: return null
        val instant = Instant.ofEpochMilli(millis)
        val formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm", Locale.GERMAN)
        return formatter.format(instant.atZone(ZoneId.systemDefault()))
    }

    companion object {
        val KEY_HOUSEHOLD_SIZE = SettingsKeys.HOUSEHOLD_SIZE
        val KEY_DAILY_KCAL_PER_PERSON = SettingsKeys.DAILY_KCAL_PER_PERSON
        val KEY_AGE_GROUPS = SettingsKeys.AGE_GROUPS
        val KEY_SERVER_URL = SettingsKeys.SERVER_URL
        val KEY_ACCESS_TOKEN = SettingsKeys.AUTH_ACCESS_TOKEN
        val KEY_REFRESH_TOKEN = SettingsKeys.AUTH_REFRESH_TOKEN
        val KEY_AUTH_USERNAME = SettingsKeys.AUTH_USERNAME
        val KEY_SYNC_LAST_TIMESTAMP = SettingsKeys.SYNC_LAST_TIMESTAMP
        val KEY_OPENAI_API_KEY = SettingsKeys.OPENAI_API_KEY
    }
}
