package com.github.nullptroma.wallenc.domain.vault.errors

import com.github.nullptroma.wallenc.domain.errors.WallencException
import com.github.nullptroma.wallenc.domain.errors.toWallencException
import com.github.nullptroma.wallenc.domain.vault.network.yandexdisk.YandexDiskAuthException
import retrofit2.HttpException
import java.io.FileNotFoundException
import java.io.IOException

fun Throwable.toVaultWallencException(): WallencException = when (this) {
    is WallencException -> this
    is YandexDiskAuthException -> WallencException.Auth.Failed()
    is HttpException -> WallencException.Network.HttpFailed(
        operation = "http",
        statusCode = code(),
        cause = this,
    )
    is FileNotFoundException -> WallencException.Storage.FileNotFound()
    is IOException -> mapVaultIo(this)
    is IllegalStateException -> mapIllegalState(this)
    is IllegalArgumentException -> mapIllegalArgument(this)
    else -> toWallencException()
}

private fun mapVaultIo(e: IOException): WallencException {
    val msg = e.message.orEmpty()
    return when {
        msg.contains("OAuth token is missing", ignoreCase = true) ->
            WallencException.Auth.TokenMissing()
        msg.contains("HTTP 423", ignoreCase = true) || msg.contains("423 after retries", ignoreCase = true) ->
            WallencException.Network.ResourceLocked()
        msg.equals("timeout", ignoreCase = true) ||
            msg.contains("timed out", ignoreCase = true) ||
            msg.contains("async operation timed out", ignoreCase = true) ->
            WallencException.Network.OperationTimedOut()
        msg.contains("async operation failed", ignoreCase = true) ->
            WallencException.Network.OperationFailed()
        else -> WallencException.Network.IoFailed(e)
    }
}

private fun mapIllegalState(e: IllegalStateException): WallencException = when {
    e.message == "Not a file" -> WallencException.Storage.NotAFile()
    e.message == "Not a directory" -> WallencException.Storage.NotADirectory()
    e.message?.startsWith("Path segment is a file:") == true -> WallencException.Storage.PathIsFile()
    e.message?.startsWith("Cannot openWrite over directory:") == true ->
        WallencException.Storage.CannotWriteOverDirectory()
    e.message?.startsWith("Expected file after upload:") == true ->
        WallencException.Storage.UnexpectedState()
    else -> WallencException.Storage.UnexpectedState()
}

private fun mapIllegalArgument(e: IllegalArgumentException): WallencException = when {
    e.message == "Deleting root path is forbidden" -> WallencException.Storage.DeleteRootForbidden()
    else -> WallencException.Unknown(e)
}
