package com.tt.honeyDue.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.tt.honeyDue.data.DataManager
import com.tt.honeyDue.data.IDataManager
import com.tt.honeyDue.models.*
import com.tt.honeyDue.network.APILayer
import com.tt.honeyDue.network.ApiResult
import com.tt.honeyDue.util.ImageCompressor
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch

/**
 * DocumentViewModel — read-state derived from [IDataManager].
 *
 * [documentsState] and [documentDetailState] are reactive projections of
 * [IDataManager.documents] / [IDataManager.documentDetail]. Mutation-
 * feedback fields (create/update/delete/download/deleteImage/uploadImage)
 * remain independent [MutableStateFlow]s — they're one-shot results, not
 * cached data.
 */
class DocumentViewModel(
    private val dataManager: IDataManager = DataManager,
    initialSelectedDocumentId: Int? = null,
) : ViewModel() {

    // ---------- Read state ----------

    val documentsState: StateFlow<ApiResult<List<Document>>> =
        dataManager.documents
            .map { list -> if (list.isNotEmpty()) ApiResult.Success(list) else ApiResult.Idle }
            .stateIn(
                viewModelScope,
                SharingStarted.Eagerly,
                dataManager.documents.value
                    .takeIf { it.isNotEmpty() }
                    ?.let { ApiResult.Success(it) } ?: ApiResult.Idle,
            )

    // `initialSelectedDocumentId` seeds this in construction order so the
    // `stateIn` initial-value closure below observes the selected id *and*
    // the seeded `dataManager.documentDetail[id]` on first subscription —
    // used by the parity-gallery snapshot harness to render populated
    // detail screens on the very first composition frame.
    private val _selectedDocumentId = MutableStateFlow<Int?>(initialSelectedDocumentId)

    val documentDetailState: StateFlow<ApiResult<Document>> =
        combine(_selectedDocumentId, dataManager.documentDetail) { id, map ->
            if (id == null) ApiResult.Idle
            else map[id]?.let { ApiResult.Success(it) } ?: ApiResult.Idle
        }.stateIn(
            viewModelScope,
            SharingStarted.Eagerly,
            _selectedDocumentId.value?.let { id ->
                dataManager.documentDetail.value[id]?.let { ApiResult.Success(it) }
            } ?: ApiResult.Idle,
        )

    fun selectDocument(id: Int?) {
        _selectedDocumentId.value = id
    }

    // ---------- Loading / error ----------

    private val _isLoading = MutableStateFlow(false)
    val isLoading: StateFlow<Boolean> = _isLoading
    private val _loadError = MutableStateFlow<String?>(null)
    val loadError: StateFlow<String?> = _loadError

    // ---------- Mutation-feedback ----------

    private val _createState = MutableStateFlow<ApiResult<Document>>(ApiResult.Idle)
    val createState: StateFlow<ApiResult<Document>> = _createState

    private val _updateState = MutableStateFlow<ApiResult<Document>>(ApiResult.Idle)
    val updateState: StateFlow<ApiResult<Document>> = _updateState

    private val _deleteState = MutableStateFlow<ApiResult<Unit>>(ApiResult.Idle)
    val deleteState: StateFlow<ApiResult<Unit>> = _deleteState

    private val _downloadState = MutableStateFlow<ApiResult<ByteArray>>(ApiResult.Idle)
    val downloadState: StateFlow<ApiResult<ByteArray>> = _downloadState

    private val _deleteImageState = MutableStateFlow<ApiResult<Document>>(ApiResult.Idle)
    val deleteImageState: StateFlow<ApiResult<Document>> = _deleteImageState

    private val _uploadImageState = MutableStateFlow<ApiResult<Document>>(ApiResult.Idle)
    val uploadImageState: StateFlow<ApiResult<Document>> = _uploadImageState

    // ---------- Loaders (write-through to DataManager) ----------

    fun loadDocuments(
        residenceId: Int? = null,
        documentType: String? = null,
        category: String? = null,
        contractorId: Int? = null,
        isActive: Boolean? = null,
        expiringSoon: Int? = null,
        tags: String? = null,
        search: String? = null,
        forceRefresh: Boolean = false
    ) {
        viewModelScope.launch {
            _isLoading.value = true
            _loadError.value = null
            _loadError.value = (APILayer.getDocuments(
                residenceId = residenceId,
                documentType = documentType,
                category = category,
                contractorId = contractorId,
                isActive = isActive,
                expiringSoon = expiringSoon,
                tags = tags,
                search = search,
                forceRefresh = forceRefresh
            ) as? ApiResult.Error)?.message
            _isLoading.value = false
        }
    }

    /**
     * Loads all documents without any filters - filtering is done client-side.
     * This reduces API calls when switching tabs or applying filters.
     */
    fun loadAllDocuments(
        residenceId: Int? = null,
        forceRefresh: Boolean = false
    ) {
        viewModelScope.launch {
            _isLoading.value = true
            _loadError.value = null
            _loadError.value = (APILayer.getDocuments(
                residenceId = residenceId,
                forceRefresh = forceRefresh
            ) as? ApiResult.Error)?.message
            _isLoading.value = false
        }
    }

    fun loadDocumentDetail(id: Int) {
        viewModelScope.launch {
            _selectedDocumentId.value = id
            _isLoading.value = true
            _loadError.value = null
            _loadError.value = (APILayer.getDocument(id) as? ApiResult.Error)?.message
            _isLoading.value = false
        }
    }

    fun createDocument(
        title: String,
        documentType: String,
        residenceId: Int,
        description: String? = null,
        category: String? = null,
        tags: String? = null,
        notes: String? = null,
        contractorId: Int? = null,
        isActive: Boolean = true,
        // Warranty-specific fields
        itemName: String? = null,
        modelNumber: String? = null,
        serialNumber: String? = null,
        provider: String? = null,
        providerContact: String? = null,
        claimPhone: String? = null,
        claimEmail: String? = null,
        claimWebsite: String? = null,
        purchaseDate: String? = null,
        startDate: String? = null,
        endDate: String? = null,
        // Images
        images: List<com.tt.honeyDue.platform.ImageData> = emptyList()
    ) {
        viewModelScope.launch {
            _createState.value = ApiResult.Loading
            // Compress images and convert to ByteArrays
            val fileBytesList = if (images.isNotEmpty()) {
                images.map { ImageCompressor.compressImage(it) }
            } else null

            val fileNamesList = if (images.isNotEmpty()) {
                images.mapIndexed { index, image ->
                    // Always use .jpg extension since we compress to JPEG
                    val baseName = image.fileName.ifBlank { "image_$index" }
                    if (baseName.endsWith(".jpg", ignoreCase = true) ||
                        baseName.endsWith(".jpeg", ignoreCase = true)) {
                        baseName
                    } else {
                        // Remove any existing extension and add .jpg
                        baseName.substringBeforeLast('.', baseName) + ".jpg"
                    }
                }
            } else null

            val mimeTypesList = if (images.isNotEmpty()) {
                images.map { "image/jpeg" }
            } else null

            _createState.value = APILayer.createDocument(
                title = title,
                documentType = documentType,
                residenceId = residenceId,
                description = description,
                category = category,
                tags = tags,
                notes = notes,
                contractorId = contractorId,
                isActive = isActive,
                itemName = itemName,
                modelNumber = modelNumber,
                serialNumber = serialNumber,
                provider = provider,
                providerContact = providerContact,
                claimPhone = claimPhone,
                claimEmail = claimEmail,
                claimWebsite = claimWebsite,
                purchaseDate = purchaseDate,
                startDate = startDate,
                endDate = endDate,
                fileBytes = null,
                fileName = null,
                mimeType = null,
                fileBytesList = fileBytesList,
                fileNamesList = fileNamesList,
                mimeTypesList = mimeTypesList
            )
        }
    }

    fun updateDocument(
        id: Int,
        title: String,
        documentType: String,
        description: String? = null,
        category: String? = null,
        tags: String? = null,
        notes: String? = null,
        contractorId: Int? = null,
        isActive: Boolean = true,
        // Warranty-specific fields
        itemName: String? = null,
        modelNumber: String? = null,
        serialNumber: String? = null,
        provider: String? = null,
        providerContact: String? = null,
        claimPhone: String? = null,
        claimEmail: String? = null,
        claimWebsite: String? = null,
        purchaseDate: String? = null,
        startDate: String? = null,
        endDate: String? = null,
        // Images
        images: List<com.tt.honeyDue.platform.ImageData> = emptyList()
    ) {
        viewModelScope.launch {
            _updateState.value = ApiResult.Loading
            // First, update the document metadata
            val updateResult = APILayer.updateDocument(
                id = id,
                title = title,
                documentType = documentType,
                description = description,
                category = category,
                tags = tags,
                notes = notes,
                contractorId = contractorId,
                isActive = isActive,
                itemName = itemName,
                modelNumber = modelNumber,
                serialNumber = serialNumber,
                provider = provider,
                providerContact = providerContact,
                claimPhone = claimPhone,
                claimEmail = claimEmail,
                claimWebsite = claimWebsite,
                purchaseDate = purchaseDate,
                startDate = startDate,
                endDate = endDate
            )

            // If update succeeded and there are new images, upload them
            if (updateResult is ApiResult.Success && images.isNotEmpty()) {
                var uploadFailed = false
                for ((index, image) in images.withIndex()) {
                    // Compress the image
                    val compressedBytes = ImageCompressor.compressImage(image)

                    // Determine filename with .jpg extension
                    val fileName = if (image.fileName.isNotBlank()) {
                        val baseName = image.fileName
                        if (baseName.endsWith(".jpg", ignoreCase = true) ||
                            baseName.endsWith(".jpeg", ignoreCase = true)) {
                            baseName
                        } else {
                            baseName.substringBeforeLast('.', baseName) + ".jpg"
                        }
                    } else {
                        "image_$index.jpg"
                    }

                    val uploadResult = APILayer.uploadDocumentImage(
                        documentId = id,
                        imageBytes = compressedBytes,
                        fileName = fileName,
                        mimeType = "image/jpeg"
                    )

                    if (uploadResult is ApiResult.Error) {
                        uploadFailed = true
                        _updateState.value = ApiResult.Error(
                            "Document updated but failed to upload image: ${uploadResult.message}",
                            uploadResult.code
                        )
                        break
                    }
                }

                // If all uploads succeeded, use the last uploaded document (has all images)
                if (!uploadFailed) {
                    _updateState.value = updateResult
                }
            } else {
                _updateState.value = updateResult
            }
        }
    }

    fun deleteDocument(id: Int) {
        viewModelScope.launch {
            _deleteState.value = ApiResult.Loading
            _deleteState.value = APILayer.deleteDocument(id)
        }
    }

    fun downloadDocument(url: String) {
        viewModelScope.launch {
            _downloadState.value = ApiResult.Loading
            _downloadState.value = APILayer.downloadDocument(url)
        }
    }

    fun resetCreateState() {
        _createState.value = ApiResult.Idle
    }

    fun resetUpdateState() {
        _updateState.value = ApiResult.Idle
    }

    fun resetDeleteState() {
        _deleteState.value = ApiResult.Idle
    }

    fun resetDownloadState() {
        _downloadState.value = ApiResult.Idle
    }

    fun deleteDocumentImage(documentId: Int, imageId: Int) {
        viewModelScope.launch {
            _deleteImageState.value = ApiResult.Loading
            _deleteImageState.value = APILayer.deleteDocumentImage(documentId, imageId)
        }
    }

    fun uploadDocumentImage(
        documentId: Int,
        imageData: com.tt.honeyDue.platform.ImageData,
        caption: String? = null
    ) {
        viewModelScope.launch {
            _uploadImageState.value = ApiResult.Loading
            val compressedBytes = ImageCompressor.compressImage(imageData)
            val fileName = if (imageData.fileName.isNotBlank()) {
                val baseName = imageData.fileName
                if (baseName.endsWith(".jpg", ignoreCase = true) ||
                    baseName.endsWith(".jpeg", ignoreCase = true)) {
                    baseName
                } else {
                    baseName.substringBeforeLast('.', baseName) + ".jpg"
                }
            } else {
                "image.jpg"
            }
            _uploadImageState.value = APILayer.uploadDocumentImage(
                documentId = documentId,
                imageBytes = compressedBytes,
                fileName = fileName,
                mimeType = "image/jpeg",
                caption = caption
            )
        }
    }

    fun resetDeleteImageState() {
        _deleteImageState.value = ApiResult.Idle
    }

    fun resetUploadImageState() {
        _uploadImageState.value = ApiResult.Idle
    }
}
