package com.syncflow.ui.browser

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.syncflow.data.providers.ProviderFactory
import com.syncflow.data.repository.AccountRepository
import com.syncflow.domain.model.RemoteFile
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import javax.inject.Inject

data class BrowserState(
    val accountId: Long = -1L,
    val currentPath: String = "/",
    val pathStack: List<String> = listOf("/"),
    val entries: List<RemoteFile> = emptyList(),
    val isLoading: Boolean = false,
    val error: String? = null,
)

@HiltViewModel
class RemoteBrowserViewModel @Inject constructor(
    private val accountRepository: AccountRepository,
    private val providerFactory: ProviderFactory,
) : ViewModel() {

    private val _state = MutableStateFlow(BrowserState())
    val state = _state.asStateFlow()

    private var loadJob: Job? = null

    fun init(accountId: Long, startPath: String = "/") {
        loadJob?.cancel()
        _state.value = BrowserState(accountId = accountId, currentPath = startPath, pathStack = listOf(startPath), isLoading = true)
        loadJob = loadPath(accountId, startPath)
    }

    fun navigateTo(path: String) {
        val accountId = _state.value.accountId
        loadJob?.cancel()
        _state.update { s -> s.copy(currentPath = path, pathStack = s.pathStack + path, isLoading = true, entries = emptyList(), error = null) }
        loadJob = loadPath(accountId, path)
    }

    fun navigateUp(): Boolean {
        val stack = _state.value.pathStack
        if (stack.size <= 1) return false
        val newStack = stack.dropLast(1)
        val parent = newStack.last()
        loadJob?.cancel()
        _state.update { it.copy(currentPath = parent, pathStack = newStack, isLoading = true, entries = emptyList(), error = null) }
        loadJob = loadPath(_state.value.accountId, parent)
        return true
    }

    fun navigateToBreadcrumb(path: String) {
        val stack = _state.value.pathStack
        val idx = stack.lastIndexOf(path)
        val newStack = if (idx >= 0) stack.take(idx + 1) else listOf(path)
        loadJob?.cancel()
        _state.update { it.copy(currentPath = path, pathStack = newStack, isLoading = true, entries = emptyList(), error = null) }
        loadJob = loadPath(_state.value.accountId, path)
    }

    fun createFolder(name: String) {
        val s = _state.value
        val newPath = if (s.currentPath.trimEnd('/') == "") "/$name" else "${s.currentPath.trimEnd('/')}/$name"
        viewModelScope.launch {
            val account = accountRepository.getAccount(s.accountId) ?: return@launch
            val provider = runCatching { providerFactory.create(account) }.getOrElse { return@launch }
            provider.createDirectory(newPath)
                .onSuccess { retry() }
                .onFailure { e -> _state.update { it.copy(error = "Could not create folder: ${e.message}") } }
        }
    }

    fun retry() {
        val s = _state.value
        if (s.accountId == -1L) return
        loadJob?.cancel()
        _state.update { it.copy(isLoading = true, error = null) }
        loadJob = loadPath(s.accountId, s.currentPath)
    }

    private fun loadPath(accountId: Long, path: String): Job = viewModelScope.launch {
        val account = accountRepository.getAccount(accountId)
        if (account == null) {
            _state.update { it.copy(isLoading = false, error = "Account not found") }
            return@launch
        }
        val provider = runCatching { providerFactory.create(account) }.getOrElse { e ->
            _state.update { it.copy(isLoading = false, error = e.message ?: "Failed to create provider") }
            return@launch
        }
        provider.listFiles(path)
            .onSuccess { files ->
                _state.update { it.copy(isLoading = false, entries = files.sortedWith(compareBy({ !it.isDirectory }, { it.name.lowercase() }))) }
            }
            .onFailure { e ->
                _state.update { it.copy(isLoading = false, error = e.message ?: "Failed to list files") }
            }
    }
}
