package com.alttd.altitudeweb.database.litebans;

import com.alttd.altitudeweb.type_handler.UUIDTypeHandler;
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;
import java.util.UUID;

public interface UUIDHistoryMapper {

    int PAGE_SIZE = 100;

    @Results({
            @Result(property = "uuid", column = "uuid", javaType = UUID.class, typeHandler = UUIDTypeHandler.class),
            @Result(property = "punishedName", column = "punished_name"),
            @Result(property = "reason", column = "reason"),
            @Result(property = "bannedByUuid", column = "banned_by_uuid", javaType = UUID.class, typeHandler = UUIDTypeHandler.class),
            @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.${uuid_column} = #{uuid}
            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 = "uuid", column = "uuid", javaType = UUID.class, typeHandler = UUIDTypeHandler.class),
            @Result(property = "punishedName", column = "punished_name"),
            @Result(property = "reason", column = "reason"),
            @Result(property = "bannedByUuid", column = "banned_by_uuid", javaType = UUID.class, typeHandler = UUIDTypeHandler.class),
            @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.${uuid_column} = #{uuid}
            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(HistoryType historyType, UserType userType, UUID uuid, int page) {
        return switch (historyType) {
            case ALL -> getRecentAll(userType, uuid, page);
            case BANS -> getRecentBans(userType, uuid, page);
            case MUTES -> getRecentMutes(userType, uuid, page);
            case KICKS -> getRecentKicks(userType, uuid, page);
            case WARNS -> getRecentWarns(userType, uuid, page);
        };
    }

    private List<HistoryRecord> getRecent(String tableName, UserType userType, 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(UserType userType, 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 List<HistoryRecord> getRecentBans(UserType userType, UUID uuid, int page) {
        return addType(getRecent("litebans_bans", userType, uuid, page), "ban");
    }

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

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

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

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

}
