package com.alttd.altitudeweb.database.litebans;

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;

import java.util.List;
import java.util.UUID;

public interface UUIDHistoryMapper {

    int PAGE_SIZE = 10;

    @Results({
            @Result(property = "id", column = "id"),
            @Result(property = "uuid", column = "uuid"),
            @Result(property = "punishedName", column = "punished_name"),
            @Result(property = "reason", column = "reason"),
            @Result(property = "bannedByUuid", column = "banned_by_uuid"),
            @Result(property = "bannedByName", column = "banned_by_name"),
            @Result(property = "removedByName", column = "removed_by_name"),
            @Result(property = "time", column = "time"),
            @Result(property = "until", column = "until"),
            @Result(property = "removedByReason", column = "removed_by_reason"),
            @Result(property = "type", column = "type")
    })
    @Select("""
            SELECT id, all_punishments.uuid, user_lookup.name AS punished_name, reason, banned_by_uuid, banned_by_name,
                   removed_by_name, time, until, removed_by_reason, type
            FROM all_punishments
            INNER JOIN user_lookup
                ON user_lookup.uuid = all_punishments.uuid
            WHERE all_punishments.${uuid_column} = #{uuid}
            ORDER BY time DESC
            LIMIT #{limit} OFFSET #{offset}
            """)
    List<HistoryRecord> getRecentAllHistory(@Param("uuid") String uuid,
                                            @Param("uuid_column") String uuidColumn,
                                            @Param("limit") int limit,
                                            @Param("offset") int offset);

    @Results({
            @Result(property = "id", column = "id"),
            @Result(property = "uuid", column = "uuid"),
            @Result(property = "punishedName", column = "punished_name"),
            @Result(property = "reason", column = "reason"),
            @Result(property = "bannedByUuid", column = "banned_by_uuid"),
            @Result(property = "bannedByName", column = "banned_by_name"),
            @Result(property = "removedByName", column = "removed_by_name"),
            @Result(property = "time", column = "time"),
            @Result(property = "until", column = "until"),
            @Result(property = "removedByReason", column = "removed_by_reason")
    })
    @Select("""
            SELECT punishment.id, punishment.uuid, user_lookup.name AS punished_name, reason, banned_by_uuid, banned_by_name,
                   removed_by_name, time, until, removed_by_reason
            FROM ${tableName} AS punishment
            INNER JOIN user_lookup ON user_lookup.uuid = punishment.uuid
            WHERE punishment.${uuid_column} = #{uuid}
            ORDER BY time DESC
            LIMIT #{limit} OFFSET #{offset}
            """)
    List<HistoryRecord> getRecentHistory(@Param("tableName") String tableName,
                                         @Param("uuid") String uuid,
                                         @Param("uuid_column") String uuidColumn,
                                         @Param("limit") int limit,
                                         @Param("offset") int offset);

    default List<HistoryRecord> getRecent(@NotNull HistoryType historyType, @NotNull UserType userType,
                                          @NotNull UUID uuid, int page) {
        return switch (historyType) {
            case ALL -> getRecentAll(userType, uuid, page);
            case BAN -> getRecentBans(userType, uuid, page);
            case MUTE -> getRecentMutes(userType, uuid, page);
            case KICK -> getRecentKicks(userType, uuid, page);
            case WARN -> getRecentWarns(userType, uuid, page);
        };
    }

    default List<HistoryRecord> getAllHistoryForUUID(@NotNull UUID uuid) {
        return getRecentAllHistory(uuid.toString(), "uuid", 100, 0);
    }

    private List<HistoryRecord> getRecent(@NotNull String tableName, @NotNull UserType userType,
                                          @NotNull UUID uuid, int page) {
        int offset = page * PAGE_SIZE;
        int limit = PAGE_SIZE;
        return switch (userType) {
            case PLAYER -> getRecentHistory(tableName, uuid.toString(), "uuid", limit, offset);
            case STAFF -> getRecentHistory(tableName, uuid.toString(), "banned_by_uuid", limit, offset);
        };
    }

    private List<HistoryRecord> getRecentAll(@NotNull UserType userType, @NotNull UUID uuid, int page) {
        int offset = page * PAGE_SIZE;
        int limit = PAGE_SIZE;
        return switch (userType) {
            case PLAYER -> getRecentAllHistory(uuid.toString(), "name",
                                               limit, offset);
            case STAFF -> getRecentAllHistory(uuid.toString(), "banned_by_name",
                                              limit, offset);
        };
    }

    private @NotNull List<HistoryRecord> getRecentBans(@NotNull UserType userType, @NotNull UUID uuid, int page) {
        return addType(getRecent("litebans_bans", userType, uuid, page), "ban");
    }

    private @NotNull List<HistoryRecord> getRecentKicks(@NotNull UserType userType, @NotNull UUID uuid, int page) {
        return addType(getRecent("litebans_kicks", userType, uuid, page), "kick");
    }

    private @NotNull List<HistoryRecord> getRecentMutes(@NotNull UserType userType, @NotNull UUID uuid, int page) {
        return addType(getRecent("litebans_mutes", userType, uuid, page), "mute");
    }

    private @NotNull List<HistoryRecord> getRecentWarns(@NotNull UserType userType, @NotNull UUID uuid, int page) {
        return addType(getRecent("litebans_warnings", userType, uuid, page), "warn");
    }

    @Contract("_, _ -> param1")
    private @NotNull List<HistoryRecord> addType(@NotNull List<HistoryRecord> historyRecords, @NotNull String type) {
        historyRecords.forEach(historyRecord -> historyRecord.setType(type));
        return historyRecords;
    }

}
