package com.example.dtf.api

import com.example.dtf.dto.Credentials
import com.example.dtf.dto.EditPostDto
import com.example.dtf.dto.MeUser
import com.example.dtf.dto.NewCommentDto
import com.example.dtf.dto.NewPostDto
import com.example.dtf.dto.Token
import com.example.dtf.dto.remote.CategoriesResponse
import com.example.dtf.dto.remote.CommentsResponse
import com.example.dtf.dto.remote.PostsResponse
import com.example.dtf.models.Category
import com.example.dtf.models.Comment
import com.example.dtf.models.Post
import com.example.dtf.models.User
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.http.POST
import retrofit2.Retrofit
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Path
import retrofit2.http.Query
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import retrofit2.http.Header

interface ServerService {
    @POST("auth/login")
    suspend fun login(
        @Body credentials: Credentials
    ): Token

    @POST("auth/register")
    suspend fun register(
        @Body credentials: Credentials
    ): String

    @GET("user/me")
    suspend fun getCurrentUser(): MeUser

    @GET("category")
    suspend fun getCategories(
        @Query("offset") offset: Int?,
        @Query("limit") limit: Int?
    ): CategoriesResponse

    @GET("post")
    suspend fun getPosts(
        @Query("category") category: Int?,
        @Query("offset") offset: Int?,
        @Query("limit") limit: Int?
    ): PostsResponse

    @GET("post/{postId}")
    suspend fun getPost(
        @Path("postId") postId: Int
    ): Post

    @POST("post")
    suspend fun createPost(
        @Body post: NewPostDto
    )

    @POST("post/{postId}")
    suspend fun updatePost(
        @Path("postId") postId: Int,
        @Body post: EditPostDto
    )

    @GET("comment")
    suspend fun getComments(
        @Query("postId") postId: Int?,
        @Query("offset") offset: Int?,
        @Query("limit") limit: Int?
    ): CommentsResponse

    @GET("comment/{commentId}")
    suspend fun getComment(
        @Path("commentId") commentId: Int
    ): Comment

    @POST("comment")
    suspend fun createComment(
        @Body comment: NewCommentDto
    )

    @POST("post/{postId}/like")
    suspend fun likePost(
        @Path("postId") postId: Int
    )

    @GET("post/{postId}/liked")
    suspend fun postIsLiked(
        @Path("postId") postId: Int
    ): Boolean

    @GET("post/{postId}/likes")
    suspend fun getPostLikes(
        @Path("postId") postId: Int
    ): Int

    @GET("user/{userId}")
    suspend fun getUser(
        @Path("userId") userId: Int
    ): User

    companion object {
        private const val BASE_URL = "http://192.168.1.9:8000/"

        private var _token: String = ""

        @Volatile
        private var INSTANCE: ServerService? = null

        fun getInstance(): ServerService {
            return INSTANCE ?: synchronized(this) {
                val logger = HttpLoggingInterceptor()
                logger.level = HttpLoggingInterceptor.Level.BASIC
                val client = OkHttpClient.Builder()
                    .addInterceptor(logger)
                    .addInterceptor {
                        val originalRequest = it.request()
                        if (_token.isEmpty()) {
                            it.proceed(originalRequest)
                        } else {
                            it.proceed(
                                originalRequest
                                    .newBuilder()
                                    .header("Authorization", "Bearer $_token")
                                    .method(originalRequest.method, originalRequest.body)
                                    .build()
                            )
                        }
                    }
                    .build()
                return Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .client(client)
                    .addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
                    .build()
                    .create(ServerService::class.java)
                    .also { INSTANCE = it }
            }
        }

        fun setToken(token: String) {
            _token = token
        }
    }
}