package com.straice.smoothdoors.mixin;

import com.straice.smoothdoors.config.SddConfigManager;
import com.straice.smoothdoors.util.ConnectedUtil;
import com.straice.smoothdoors.util.SyncGuard;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.DoorBlock;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.state.property.Properties;
import net.minecraft.util.ActionResult;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.block.WireOrientation;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

@Mixin(DoorBlock.class)
public class DoorBlockMixin {

    @Inject(method = "onUse", at = @At("TAIL"))
    private void sdd$onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit,
                           CallbackInfoReturnable<ActionResult> cir) {
        if (world.isClient) return;
        if (!SddConfigManager.get().connectDoors) return;
        if (SyncGuard.isIn()) return;

        BlockPos lower = ConnectedUtil.getDoorLowerPos(pos, state);
        BlockState lowerNow = world.getBlockState(lower);
        if (!lowerNow.contains(Properties.OPEN)) return;

        boolean openNow = lowerNow.get(Properties.OPEN);
        BlockPos mateLower = ConnectedUtil.findPairedDoorLower(world, lower, lowerNow);
        if (mateLower == null) return;

        SyncGuard.run(() -> ConnectedUtil.setDoorOpen(world, mateLower, openNow));
    }

    // 1.21.8+: neighborUpdate(..., @Nullable WireOrientation wireOrientation, boolean notify)
    @Inject(method = "neighborUpdate", at = @At("TAIL"))
    private void sdd$neighborUpdate(BlockState state, World world, BlockPos pos, Block block,
                                    @Nullable WireOrientation wireOrientation, boolean notify, CallbackInfo ci) {
        if (world.isClient) return;
        if (!SddConfigManager.get().connectDoors) return;
        if (!SddConfigManager.get().redstoneDoubleDoors) return;
        if (SyncGuard.isIn()) return;

        BlockPos lower = ConnectedUtil.getDoorLowerPos(pos, state);
        BlockState lowerNow = world.getBlockState(lower);
        if (!lowerNow.contains(Properties.OPEN)) return;

        boolean openNow = lowerNow.get(Properties.OPEN);
        BlockPos mateLower = ConnectedUtil.findPairedDoorLower(world, lower, lowerNow);
        if (mateLower == null) return;

        SyncGuard.run(() -> ConnectedUtil.setDoorOpen(world, mateLower, openNow));
    }
}
