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 java.util.List;

public interface NameHistoryMapper {

    int PAGE_SIZE = 100;

    /**
     * Retrieves a list of all types of recent punishment history records filtered based on the given parameters sorted
     * in descending time order. This result does NOT contain kicks history
     *
     * @param partialName a partial or complete name of the user to filter the records, case-insensitive
     * @param nameColumn  the column name in the database indicating the name to use for filtering
     * @param limit       the maximum number of records to fetch
     * @param offset      the starting offset position of the result set
     *
     * @return a list of {@link HistoryRecord} objects that match the specified filters, ordered by time in descending
     * order
     */
    @Results({
            @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 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.${name_column} LIKE #{partialName}
            ORDER BY time DESC
            LIMIT #{limit} OFFSET #{offset}
            """)
    List<HistoryRecord> getRecentAllHistory(@Param("partialName") String partialName,
                                            @Param("name_column") String nameColumn,
                                            @Param("limit") int limit,
                                            @Param("offset") int offset);

    /**
     * Retrieves a list of a specific type of recent punishment history records filtered based on the provided
     * parameters. The records are sorted in descending order by time and limited to a specified range.
     *
     * @param tableName   the name of the database table to query the history records from
     * @param partialName a partial or complete name of the user to filter the records, case-insensitive
     * @param nameColumn  the column name in the database indicating the name to use for filtering
     * @param limit       the maximum number of records to fetch
     * @param offset      the starting offset position of the result set
     *
     * @return a list of {@link HistoryRecord} objects that match the specified filters, sorted by time in descending
     * order
     */
    @Results({
            @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.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.${name_column} LIKE #{partialName}
            LIMIT #{limit} OFFSET #{offset}
            """)
    List<HistoryRecord> getRecentHistory(@Param("tableName") String tableName,
                                         @Param("partialName") String partialName,
                                         @Param("name_column") String nameColumn,
                                         @Param("limit") int limit,
                                         @Param("offset") int offset);

    default List<HistoryRecord> getRecent(HistoryType historyType, UserType userType, String partialName,
                                          int page) {
        return switch (historyType) {
            case ALL -> getRecentAll(userType, partialName, page);
            case BANS -> getRecentBans(userType, partialName, page);
            case MUTES -> getRecentMutes(userType, partialName, page);
            case KICKS -> getRecentKicks(userType, partialName, page);
            case WARNS -> getRecentWarns(userType, partialName, page);
        };
    }

    private List<HistoryRecord> getRecent(String tableName, UserType userType, String partialName,
                                          int page) {
        int offset = page * PAGE_SIZE;
        int limit = PAGE_SIZE;
        return switch (userType) {
            case PLAYER -> getRecentHistory(tableName, partialName.toLowerCase() + "%", "name",
                                            limit, offset);
            case STAFF -> getRecentHistory(tableName, partialName.toLowerCase() + "%", "banned_by_name",
                                           limit, offset);
        };
    }

    private List<HistoryRecord> getRecentAll(UserType userType, String partialName, int page) {
        int offset = page * PAGE_SIZE;
        int limit = PAGE_SIZE;
        return switch (userType) {
            case PLAYER -> getRecentAllHistory(partialName.toLowerCase() + "%", "name",
                                               limit, offset);
            case STAFF -> getRecentAllHistory(partialName.toLowerCase() + "%", "banned_by_name",
                                              limit, offset);
        };
    }

    private List<HistoryRecord> getRecentBans(UserType userType, String partialName, int page) {
        return addType(getRecent("litebans_bans", userType, partialName, page), "ban");
    }

    private List<HistoryRecord> getRecentKicks(UserType userType, String partialName, int page) {
        return addType(getRecent("litebans_kicks", userType, partialName, page), "kick");
    }

    private List<HistoryRecord> getRecentMutes(UserType userType, String partialName, int page) {
        return addType(getRecent("litebans_mutes", userType, partialName, page), "mute");
    }

    private List<HistoryRecord> getRecentWarns(UserType userType, String partialName, int page) {
        return addType(getRecent("litebans_warnings", userType, partialName, page), "warn");
    }

    private List<HistoryRecord> addType(List<HistoryRecord> historyRecords, String type) {
        historyRecords.forEach(historyRecord -> historyRecord.setType(type));
        return historyRecords;
    }

}
