package com.github.nullptroma.wallenc.usecases

import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
import com.github.nullptroma.wallenc.domain.encrypt.Encryptor
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
import com.github.nullptroma.wallenc.domain.interfaces.IStorageInfo
import com.github.nullptroma.wallenc.domain.interfaces.IUnlockManager
import com.github.nullptroma.wallenc.domain.tasks.TaskProgress
import kotlinx.coroutines.flow.first
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class ManageStoragesEncryptionUseCase @Inject constructor(
    private val unlockManager: IUnlockManager,
) {
    sealed interface CanEncryptResult {
        data object Allowed : CanEncryptResult
        data object UnsupportedStorageType : CanEncryptResult
        data object AlreadyEncrypted : CanEncryptResult
        data object StorageIsNotEmpty : CanEncryptResult
        data object StorageStateUnknown : CanEncryptResult
    }

    suspend fun canEncrypt(storage: IStorageInfo): CanEncryptResult {
        if (storage !is IStorage) return CanEncryptResult.UnsupportedStorageType
        if (storage.metaInfo.value.encInfo != null) return CanEncryptResult.AlreadyEncrypted

        val isEmpty = storage.isEmpty.first()
        return when (isEmpty) {
            true -> CanEncryptResult.Allowed
            false -> CanEncryptResult.StorageIsNotEmpty
            null -> CanEncryptResult.StorageStateUnknown
        }
    }

    suspend fun enableEncryption(storage: IStorageInfo, key: EncryptKey, encryptPath: Boolean) {
        when (val result = canEncrypt(storage)) {
            CanEncryptResult.Allowed -> (storage as IStorage).setEncInfo(
                Encryptor.generateEncryptionInfo(key, encryptPath)
            )
            CanEncryptResult.AlreadyEncrypted -> throw IllegalStateException("Storage is already encrypted")
            CanEncryptResult.StorageIsNotEmpty -> throw IllegalStateException("Storage is not empty")
            CanEncryptResult.StorageStateUnknown -> throw IllegalStateException("Storage state is unknown")
            CanEncryptResult.UnsupportedStorageType -> throw IllegalStateException("Unsupported storage type")
        }
    }

    suspend fun rememberStorageKey(storage: IStorageInfo, key: EncryptKey) {
        if (storage is IStorage) {
            unlockManager.rememberKey(storage, key)
            return
        }
        throw IllegalStateException("Unsupported storage type")
    }

    suspend fun openStorage(storage: IStorageInfo, key: EncryptKey, rememberPassword: Boolean): IStorageInfo {
        if (storage is IStorage) return unlockManager.open(storage, key, rememberPassword)
        throw IllegalStateException("Unsupported storage type")
    }

    suspend fun closeStorage(storage: IStorageInfo) {
        if (storage is IStorage) {
            unlockManager.close(storage)
        }
    }

    suspend fun clearAndDisableEncryption(
        storage: IStorageInfo,
        onClearProgress: suspend (TaskProgress) -> Unit = {},
    ) {
        if (storage !is IStorage) return
        storage.clearAllContent(onClearProgress)
        storage.setEncInfo(null)
        unlockManager.close(storage)
    }

}
