package com.example.wabi.domain.supabase

import android.util.Log
import com.example.wabi.models.responses.Response
import com.example.wabi.models.responses.UserResponse
import com.example.wabi.models.screens.SignUpUser
import com.example.wabi.models.supabase.Basket
import com.example.wabi.models.supabase.User
import io.github.jan.supabase.SupabaseClient
import io.github.jan.supabase.gotrue.auth
import io.github.jan.supabase.gotrue.providers.builtin.Email
import io.github.jan.supabase.gotrue.user.UserInfo
import io.github.jan.supabase.postgrest.from
import io.github.jan.supabase.postgrest.query.Columns
import io.github.jan.supabase.postgrest.query.Count
import io.github.jan.supabase.storage.storage
import javax.inject.Inject


class SupabaseServiceImpl @Inject constructor(private val supabase: SupabaseClient) :
    SupabaseService {
    override suspend fun signIn(userEmail: String, userPasword: String): Response {
        return try {
            var user = supabase.auth.signInWith(Email) {
                email = userEmail
                password = userPasword
            }
            Log.d("signIn", "The user is logged in")
            Response(user.toString())
        } catch (ex: Exception) {
            Log.e("signIn", ex.message.toString())
            Response("", ex.message.toString())
        }
    }

    override suspend fun signOut(): Response {
        return try {
            val response = supabase.auth.signOut()
            Log.d("signOut", "The user logged out")
            Response(response.toString())
        } catch (e: Exception) {
            Log.d("signOut", e.message.toString())
            Response("", e.message.toString())
        }
    }

    override suspend fun signUp(userEmail: String, userPasword: String): Response {
        return try {
            var user = supabase.auth.signUpWith(Email) {
                email = userEmail
                password = userPasword
            }
            Log.d("signUp", "The user was created")
            Response(user.toString())
        } catch (ex: Exception) {
            Log.e("signUp", ex.message.toString())
            Response("", ex.message.toString())
        }
    }

    override suspend fun addUser(user: SignUpUser): Response {
        return try {
            val userCreate = User(
                id = user.id,
                email = user.email,
                image = user.image,
                nickname = user.nickname,
                basketCode = user.basketCode
            )

            var response = supabase.from("user").insert(userCreate)

            Log.d("add user", "The user was update for create")
            Response(response.toString())
        } catch (ex: Exception) {
            Log.e("signUp", ex.message.toString())
            Response("", ex.message.toString())
        }
    }

    override suspend fun emailIsExists(userEmail: String): Boolean {
        val count = supabase.from("user").select() {
            filter {
                eq("email", userEmail)
            }
            count(Count.EXACT)
        }.countOrNull()!!

        Log.d("email is exists", "count users with added email: ${count.toString()}")
        Log.d("email is exists", "result: ${count == 1.toLong()}")
        return count == 1.toLong()
    }

    override suspend fun uploadImageToStorage(
        where: String, name: String, image: ByteArray
    ): Response {
        return try {
            var response = supabase.storage.from(where).upload(name, image, upsert = true)
            Log.d("storage", "Image $name was uploaded to $where")
            Response(response.toString())
        } catch (ex: Exception) {
            Log.e("storage", ex.message.toString())
            Response("", ex.message.toString())
        }
    }

    override suspend fun getCurrentUser(): UserInfo? {
        return supabase.auth.currentUserOrNull()
    }

    override suspend fun getUserData(userId: String): UserResponse {
        return try {
            val response = supabase.from("user").select() {
                filter {
                    eq("id", userId)
                }
                limit(count = 1)
            }.decodeSingle<User>()
            Log.d("get user", "user was got: ${response.toString()}")
            UserResponse(response)
        } catch (ex: Exception) {
            Log.d("get user", ex.message.toString())
            UserResponse(User(), error = ex.message.toString())
        }
    }

    override suspend fun resetPasswordForEmail(userEmail: String): Response {
        return try {
            val response = supabase.auth.resetPasswordForEmail(email = userEmail)
            Log.d("reset password", "Request for reset was send to email")
            Response(response.toString())
        } catch (ex: Exception) {
            Log.d("signOut", ex.message.toString())
            Response("", ex.message.toString())
        }
    }

    override suspend fun getBasket(): List<Basket> {
        return supabase.from("basket").select(
            Columns.raw(
                """ 
            id, user, product, status, count
        """.trimIndent()
            )
        ).decodeList<Basket>()
    }
}