package dev.zxq5.chatapp.android.api

import android.util.Log
import dev.zxq5.chatapp.android.BuildConfig.BASE_URL
import dev.zxq5.chatapp.android.api.model.AccountDeleteRequest
import dev.zxq5.chatapp.android.api.model.DisplayNameRequest
import dev.zxq5.chatapp.android.api.model.InviteRequest
import dev.zxq5.chatapp.android.api.model.PasswordChangeRequest
import dev.zxq5.chatapp.android.api.model.QrResponse
import dev.zxq5.chatapp.android.api.model.TOTPSixDigitCode
import dev.zxq5.chatapp.android.api.model.TotpStatus
import dev.zxq5.chatapp.android.api.model.UsernameRequest
import dev.zxq5.chatapp.android.api.model.TotpDeleteRequest
import dev.zxq5.chatapp.android.api.model.PasswordRequest
import dev.zxq5.chatapp.android.core.error.ApiResult
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.engine.android.Android
import io.ktor.client.plugins.auth.Auth
import io.ktor.client.plugins.auth.providers.BearerTokens
import io.ktor.client.plugins.auth.providers.bearer
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.request.delete
import io.ktor.client.request.get
import io.ktor.client.request.patch
import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.http.ContentType
import io.ktor.http.contentType
import io.ktor.http.isSuccess
import io.ktor.serialization.kotlinx.json.json
import kotlinx.serialization.json.Json

/**
 * Client for account settings and TOTP management.
 */
class SettingsClient(private val token: String) {
    private val http = HttpClient(Android) {
        install(ContentNegotiation) {
            json(Json { ignoreUnknownKeys = true })
        }
        install(Auth) {
            bearer {
                loadTokens { BearerTokens(token, "") }
            }
        }
    }

    suspend fun createInvite(request: InviteRequest): ApiResult<String> {
        return try {
            val response = http.post("${BASE_URL}/api/invite") {
                contentType(ContentType.Application.Json)
                setBody(request)
            }
            if (response.status.isSuccess()) {
                ApiResult.Success(response.body<String>())
            } else {
                ApiResult.HttpError(response.status.value, "Failed to create invite")
            }
        } catch (e: Exception) {
            ApiResult.NetworkError(e.localizedMessage ?: "Network error")
        }
    }

    suspend fun getTotpQr(password: String): ApiResult<QrResponse> {
        return try {
            val response = http.post("${BASE_URL}/api/totp.jpg") {
                contentType(ContentType.Application.Json)
                setBody(PasswordRequest(password))
            }
            if (response.status.isSuccess()) {
                ApiResult.Success(response.body<QrResponse>())
            } else {
                ApiResult.HttpError(response.status.value, "Failed to get QR code")
            }
        } catch (e: Exception) {
            Log.e("Chat", "Error fetching TOTP QR", e)
            ApiResult.NetworkError(e.localizedMessage ?: "Network error")
        }
    }

    suspend fun confirmTotp(code: String): ApiResult<Unit> {
        return try {
            val response = http.post("${BASE_URL}/api/totp") {
                contentType(ContentType.Application.Json)
                setBody(TOTPSixDigitCode(code))
            }
            if (response.status.isSuccess()) {
                ApiResult.Success(Unit)
            } else {
                ApiResult.HttpError(response.status.value, "Failed to confirm TOTP")
            }
        } catch (e: Exception) {
            Log.e("Chat", "Error confirming TOTP", e)
            ApiResult.NetworkError(e.localizedMessage ?: "Network error")
        }
    }

    suspend fun getTotpStatus(): ApiResult<TotpStatus> {
        return try {
            val response = http.get("${BASE_URL}/api/totp/status")
            if (response.status.isSuccess()) {
                ApiResult.Success(response.body<TotpStatus>())
            } else {
                ApiResult.HttpError(response.status.value, "Failed to get TOTP status")
            }
        } catch (e: Exception) {
            Log.e("Chat", "Error getting TOTP status", e)
            ApiResult.NetworkError(e.localizedMessage ?: "Network error")
        }
    }

    suspend fun disableTotp(password: String, totpCode: String): ApiResult<Unit> {
        return try {
            val response = http.delete("${BASE_URL}/api/totp") {
                contentType(ContentType.Application.Json)
                setBody(TotpDeleteRequest(password, totpCode))
            }
            if (response.status.isSuccess()) {
                ApiResult.Success(Unit)
            } else {
                ApiResult.HttpError(response.status.value, "Failed to disable TOTP")
            }
        } catch (e: Exception) {
            Log.e("Chat", "Error disabling TOTP", e)
            ApiResult.NetworkError(e.localizedMessage ?: "Network error")
        }
    }

    suspend fun changePassword(old: String, new: String): ApiResult<Unit> {
        return try {
            val response = http.post("${BASE_URL}/api/settings/password") {
                contentType(ContentType.Application.Json)
                setBody(PasswordChangeRequest(old, new))
            }
            if (response.status.isSuccess()) {
                ApiResult.Success(Unit)
            } else {
                ApiResult.HttpError(
                    response.status.value,
                    if (response.status.value == 401) "Old password is wrong" else "Password change failed"
                )
            }
        } catch (e: Exception) {
            Log.e("Chat", "Error changing password", e)
            ApiResult.NetworkError(e.localizedMessage ?: "Network error")
        }
    }

    suspend fun updateDisplayName(name: String?): Boolean {
        return try {
            val response = http.patch("${BASE_URL}/api/settings/display_name") {
                contentType(ContentType.Application.Json)
                setBody(DisplayNameRequest(name))
            }
            response.status.isSuccess()
        } catch (e: Exception) {
            Log.e("Chat", "Error updating display name", e)
            false
        }
    }

    suspend fun updateUsername(username: String): ApiResult<Unit> {
        return try {
            val response = http.patch("${BASE_URL}/api/settings/username") {
                contentType(ContentType.Application.Json)
                setBody(UsernameRequest(username))
            }
            if (response.status.isSuccess()) ApiResult.Success(Unit)
            else ApiResult.HttpError(response.status.value, "Failed to update username")
        } catch (e: Exception) {
            ApiResult.NetworkError(e.localizedMessage ?: "Network error")
        }
    }

    suspend fun deleteAccount(password: String, totpCode: String?): ApiResult<Unit> {
        return try {
            val response = http.delete("${BASE_URL}/api/settings") {
                contentType(ContentType.Application.Json)
                setBody(AccountDeleteRequest(password, totpCode))
            }
            if (response.status.isSuccess()) ApiResult.Success(Unit)
            else ApiResult.HttpError(response.status.value, "Failed to delete account")
        } catch (e: Exception) {
            ApiResult.NetworkError(e.localizedMessage ?: "Network error")
        }
    }
}
