package dev.zxq5.chatapp.android.api

import android.util.Log
import dev.zxq5.chatapp.android.BuildConfig
import dev.zxq5.chatapp.android.BuildConfig.BASE_URL
import dev.zxq5.chatapp.android.api.model.LoginRequest
import dev.zxq5.chatapp.android.api.model.LoginResponse
import dev.zxq5.chatapp.android.api.model.TOTPSixDigitCode
import dev.zxq5.chatapp.android.core.error.ApiResult
import dev.zxq5.chatapp.android.api.model.SignupRequest
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.engine.android.Android
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.request.header
import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.http.ContentType
import io.ktor.http.HttpHeaders
import io.ktor.http.contentType
import io.ktor.http.isSuccess
import io.ktor.serialization.kotlinx.json.json
import kotlinx.serialization.json.Json

/**
 * Client for unauthenticated and pre-authenticated (2FA) requests.
 */
object AuthClient {
    private val http = HttpClient(Android) {
        install(ContentNegotiation) {
            json(Json { ignoreUnknownKeys = true })
        }
    }

    suspend fun login(username: String, password: String): ApiResult<LoginResponse> {
        return try {
            val response = http.post("${BASE_URL}/api/login") {
                contentType(ContentType.Application.Json)
                setBody(LoginRequest(username, password))
            }
            if (response.status.isSuccess()) {
                ApiResult.Success(response.body<LoginResponse>())
            } else {
                ApiResult.HttpError(
                    status = response.status.value,
                    message = when (response.status.value) {
                        401 -> "Invalid username or password"
                        403 -> "Account suspended"
                        429 -> "Too many attempts, please wait"
                        else -> "Login failed (${response.status.value})"
                    }
                )
            }
        } catch (e: Exception) {
            Log.e("Chat", "Login network error", e)
            ApiResult.NetworkError(e.localizedMessage ?: "Network error")
        }
    }

    suspend fun signup(username: String, email: String, password: String, token: String): ApiResult<LoginResponse> {
        return try {
            val response = http.post("${BASE_URL}/api/signup") {
                contentType(ContentType.Application.Json)
                setBody(
                    SignupRequest(
                        username = username,
                        email = email,
                        password = password,
                        access_token = token
                    )
                )
            }
            if (response.status.isSuccess()) {
                ApiResult.Success(response.body<LoginResponse>())
            } else {
                ApiResult.HttpError(
                    status = response.status.value,
                    message = when (response.status.value) {
                        401 -> "Invalid access token"
                        else -> "Signup failed (${response.status.value})"
                    }
                )
            }
        } catch (e: Exception) {
            Log.e("Chat", "Signup error", e)
            ApiResult.NetworkError(e.localizedMessage ?: "Network error")
        }
    }

    suspend fun verifyTotpLogin(partialToken: String, code: String): ApiResult<LoginResponse> {
        return try {
            val response = http.post("${BASE_URL}/api/totp/verify") {
                header(HttpHeaders.Authorization, "Bearer $partialToken")
                contentType(ContentType.Application.Json)
                setBody(TOTPSixDigitCode(code))
            }
            if (response.status.isSuccess()) {
                ApiResult.Success(response.body<LoginResponse>())
            } else {
                val errorText = try { response.body<String>() } catch (e: Exception) { "Unknown error" }
                Log.e("Chat", "TOTP verify failed: ${response.status.value} - $errorText")
                ApiResult.HttpError(
                    status = response.status.value,
                    message = when (response.status.value) {
                        401 -> "Incorrect code, please try again"
                        403 -> "Session expired, please log in again"
                        429 -> "Too many attempts, please wait"
                        else -> "Verification failed (${response.status.value})"
                    }
                )
            }
        } catch (e: Exception) {
            Log.e("Chat", "TOTP verify network error", e)
            ApiResult.NetworkError(e.localizedMessage ?: "Network error")
        }
    }
}
