package de.simolzimol.mclogger.paper.listeners;

import de.simolzimol.mclogger.paper.PaperLoggerPlugin;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.event.EventBus;
import net.luckperms.api.event.log.LogPublishEvent;
import net.luckperms.api.actionlog.Action;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * Listens for LuckPerms log events and stores all permission changes.
 * Only registered when LuckPerms is loaded (softdepend).
 *
 * @author SimolZimol
 */
public class LuckPermsListener {

    private final PaperLoggerPlugin plugin;

    public LuckPermsListener(PaperLoggerPlugin plugin, LuckPerms luckPerms) {
        this.plugin = plugin;
        registerEvents(luckPerms.getEventBus());
        plugin.getLogger().info("[MCLogger] LuckPerms listener registered.");
    }

    private void registerEvents(EventBus bus) {
        bus.subscribe(plugin, LogPublishEvent.class, this::onLogPublish);
    }

    /**
     * LogPublishEvent is fired by LuckPerms whenever an action is written to
     * the action log (grant, revoke, group create/delete, track
     * add/remove, meta set, etc.).
     */
    private void onLogPublish(LogPublishEvent event) {
        Action entry = event.getEntry();

        String actorUuid   = entry.getSource().getUniqueId().toString();
        String actorName   = entry.getSource().getName();
        String targetType  = formatTargetType(entry.getTarget().getType());
        String targetId    = formatTargetId(entry.getTarget());
        String actionStr   = entry.getDescription();

        // Derive player UUID if the target is a user
        String playerUuid = null;
        String playerName = null;
        if (entry.getTarget().getType() == Action.Target.Type.USER) {
            playerUuid = entry.getTarget().getUniqueId()
                              .map(UUID::toString).orElse(null);
            playerName = entry.getTarget().getName();
        }

        // Derive event type from the action description
        String eventType = deriveEventType(actionStr);

        Map<String, Object> details = new HashMap<>();
        details.put("actor_uuid", actorUuid);
        details.put("actor_name", actorName);
        details.put("target_type", targetType);
        details.put("target_id", targetId);
        details.put("action_raw", actionStr);
        details.put("timestamp_luckperms", entry.getTimestamp().getEpochSecond());

        plugin.getDb().insertPluginEvent(
                eventType,
                "LuckPerms",
                playerUuid,
                playerName,
                actorUuid,
                actorName,
                targetType,
                targetId,
                actionStr,
                details
        );
    }

    // --------------------------------------------------------
    // Helper methods
    // --------------------------------------------------------

    private String formatTargetType(Action.Target.Type type) {
        return switch (type) {
            case USER  -> "user";
            case GROUP -> "group";
            case TRACK -> "track";
        };
    }

    private String formatTargetId(Action.Target target) {
        if (target.getUniqueId().isPresent()) {
            return target.getUniqueId().get().toString();
        }
        return target.getName();
    }

    /**
     * Maps an action description to a compact event type.
     * Beispiele:
     *   "permission set permission.node to true"  -> luckperms_permission_set
     *   "permission unset permission.node"        -> luckperms_permission_unset
     *   "parent add groupname"                    -> luckperms_parent_add
     *   "group create groupname"                  -> luckperms_group_create
     */
    private String deriveEventType(String action) {
        if (action == null) return "luckperms_unknown";
        String lower = action.toLowerCase();
        if (lower.startsWith("permission set"))    return "luckperms_permission_set";
        if (lower.startsWith("permission unset"))  return "luckperms_permission_unset";
        if (lower.startsWith("parent add"))        return "luckperms_parent_add";
        if (lower.startsWith("parent remove"))     return "luckperms_parent_remove";
        if (lower.startsWith("meta set"))          return "luckperms_meta_set";
        if (lower.startsWith("meta unset"))        return "luckperms_meta_unset";
        if (lower.startsWith("group create"))      return "luckperms_group_create";
        if (lower.startsWith("group delete"))      return "luckperms_group_delete";
        if (lower.startsWith("track create"))      return "luckperms_track_create";
        if (lower.startsWith("track delete"))      return "luckperms_track_delete";
        if (lower.startsWith("track add"))         return "luckperms_track_add";
        if (lower.startsWith("track remove"))      return "luckperms_track_remove";
        return "luckperms_action";
    }
}
