package com.nisemoe.nise.search.user

import com.nisemoe.generated.tables.references.USERS
import com.nisemoe.nise.service.AuthService
import org.jooq.Field
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController

@RestController
class UserSearchSchemaController(
    private val authService: AuthService,
) {

    companion object {

        val internalFields = listOf(
            // User fields
            InternalSchemaField("user_id", "ID", Category.user, Type.number, false, "unique identifier for a user", databaseField = USERS.USER_ID),
            InternalSchemaField("username", "Username", Category.user, Type.string, true, "user's name", databaseField = USERS.USERNAME),
            InternalSchemaField("join_date", "Join Date", Category.user, Type.datetime, false, "when the user joined", databaseField = USERS.JOIN_DATE),
            InternalSchemaField("country", "Country", Category.user, Type.flag, true, "user's country flag", databaseField = USERS.COUNTRY),
            InternalSchemaField("country_rank", "Country Rank", Category.user, Type.number, false, "ranking within user's country", databaseField = USERS.COUNTRY_RANK),
            InternalSchemaField("rank", "Rank", Category.user, Type.number, false, "global ranking", databaseField = USERS.RANK),
            InternalSchemaField("pp_raw", "User PP", Category.user, Type.number, true, "performance points", databaseField = USERS.PP_RAW),
            InternalSchemaField("accuracy", "User Accuracy", Category.user, Type.number, false, "hit accuracy percentage", databaseField = USERS.ACCURACY),
            InternalSchemaField("playcount", "Playcount", Category.user, Type.number, false, "total plays", databaseField = USERS.PLAYCOUNT),
            InternalSchemaField("total_score", "Total Score", Category.user, Type.number, false, "cumulative score", databaseField = USERS.TOTAL_SCORE),
            InternalSchemaField("ranked_score", "Ranked Score", Category.user, Type.number, false, "score from ranked maps", databaseField = USERS.RANKED_SCORE),
            InternalSchemaField("seconds_played", "Play Time", Category.user, Type.playtime, true, "total play time in seconds", databaseField = USERS.SECONDS_PLAYED),
            InternalSchemaField("count_300", "300s", Category.user, Type.number, false, "number of 300 hits", databaseField = USERS.COUNT_300),
            InternalSchemaField("count_100", "100s", Category.user, Type.number, false, "number of 100 hits", databaseField = USERS.COUNT_100),
            InternalSchemaField("count_50", "50s", Category.user, Type.number, false, "number of 50 hits", databaseField = USERS.COUNT_50),
            InternalSchemaField("count_miss", "Misses", Category.user, Type.number, false, "missed hits", databaseField = USERS.COUNT_MISS),
            InternalSchemaField("is_banned", "Is Banned", Category.user, Type.boolean, false, "is the user banned?", databaseField = USERS.IS_BANNED),
            InternalSchemaField("approx_ban_date", "Approx. ban date", Category.user, Type.datetime, false, "approximate date the user was banned at.", databaseField = USERS.APPROX_BAN_DATE),
            )

    }

    data class InternalSchemaField(
        val name: String,
        val shortName: String,
        val category: Category,
        val type: Type,
        val active: Boolean,
        val description: String,

        val isPrivileged: Boolean = false,
        val databaseField: Field<*>? = null
    )

    data class SchemaField(
        val name: String,
        val shortName: String,
        val category: Category,
        val type: Type,
        val active: Boolean,
        val description: String
    )

    enum class Category {
        user, score, beatmap
    }

    enum class Type {
        number, string, flag, grade, boolean, datetime, playtime
    }

    data class SearchSchema(
        val fields: List<SchemaField>
    )

    @GetMapping("search-user/schema")
    fun getSearchSchema(): ResponseEntity<SearchSchema> {
        // Map to SchemaField
        val isUserAdmin = authService.isAdmin()
        val fields = internalFields
            .filter {
                return@filter !(it.isPrivileged && !isUserAdmin)
            }
            .map {
            SchemaField(
                name = it.name,
                shortName = it.shortName,
                category = it.category,
                type = it.type,
                active = it.active,
                description = it.description
            )
        }

        val schema = SearchSchema(fields)
        return ResponseEntity.ok(schema)
    }

}