package pers.neige.neigeitems.action.impl;

import lombok.NonNull;
import lombok.val;
import org.jetbrains.annotations.Nullable;
import pers.neige.neigeitems.action.Action;
import pers.neige.neigeitems.action.ActionContext;
import pers.neige.neigeitems.action.ActionResult;
import pers.neige.neigeitems.action.ActionType;
import pers.neige.neigeitems.action.handler.SyncActionHandler;
import pers.neige.neigeitems.action.result.Results;
import pers.neige.neigeitems.manager.BaseActionManager;
import pers.neige.neigeitems.utils.lazy.ThreadSafeLazy;
import pers.neige.neigeitems.utils.lazy.ThreadSafeLazyBoolean;

import java.util.Locale;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;

public class StringAction extends Action {
    private final @NonNull String action;
    private final @NonNull String key;
    private final @NonNull String content;
    private final @NonNull ThreadSafeLazy<BiFunction<ActionContext, String, CompletableFuture<ActionResult>>> handler;

    public StringAction(
        @NonNull BaseActionManager manager,
        @NonNull String action
    ) {
        this(manager, action, action.split(": ", 2));
    }

    private StringAction(
        @NonNull BaseActionManager manager,
        @NonNull String action,
        @NonNull String[] keyAndContent
    ) {
        this(manager, action, keyAndContent[0].toLowerCase(Locale.ROOT), keyAndContent.length > 1 ? keyAndContent[1] : "");
    }

    public StringAction(
        @NonNull BaseActionManager manager,
        @NonNull String key,
        @NonNull String content
    ) {
        this(manager, key + ": " + content, key, content);
    }

    public StringAction(
        @NonNull BaseActionManager manager,
        @NonNull String action,
        @NonNull String key,
        @NonNull String content
    ) {
        super(manager);
        this.action = action;
        this.key = key;
        this.content = content;
        val maybeHandler = manager.getAction(this.key);
        this.handler = maybeHandler == null ? new ThreadSafeLazy<>(() -> manager.getAction(this.key)) : new ThreadSafeLazy<>(maybeHandler);
        checkAsyncSafe();
    }

    private void checkAsyncSafe() {
        this.canRunInOtherThread = new ThreadSafeLazyBoolean(() -> !(this.handler.get() instanceof SyncActionHandler));
    }

    @Override
    public @NonNull ActionType getType() {
        return ActionType.STRING;
    }

    /**
     * 将基础类型动作的执行逻辑放入 BaseActionManager 是为了给其他插件覆写的机会
     */
    @Override
    protected @NonNull CompletableFuture<ActionResult> eval(
        @NonNull BaseActionManager manager,
        @NonNull ActionContext context
    ) {
        try {
            return manager.runAction(this, context);
        } catch (Throwable throwable) {
            manager.getPlugin().getLogger().warning("动作执行异常, 动作原始内容如下:");
            for (val actionLine : action.split("\n")) {
                manager.getPlugin().getLogger().warning(actionLine);
            }
            throwable.printStackTrace();
            return CompletableFuture.completedFuture(Results.STOP);
        }
    }

    @Override
    public @NonNull CompletableFuture<ActionResult> evalAsyncSafe(@NonNull BaseActionManager manager, @NonNull ActionContext context) {
        return super.evalAsyncSafe(manager, context);
    }

    public @NonNull String getAction() {
        return action;
    }

    public @NonNull String getKey() {
        return key;
    }

    public @NonNull String getContent() {
        return content;
    }

    public @Nullable BiFunction<ActionContext, String, CompletableFuture<ActionResult>> getHandler() {
        return handler.get();
    }
}
