package com.trunksbomb.minetriad.world;

import com.mojang.serialization.MapCodec;
import com.trunksbomb.minetriad.MineTriad;
import com.trunksbomb.minetriad.blockentity.DuelTableAnimationResolver;
import com.trunksbomb.minetriad.blockentity.DuelTableBlockEntity;
import com.trunksbomb.minetriad.card.CardStackData;
import com.trunksbomb.minetriad.game.DuelSession;
import com.trunksbomb.minetriad.game.DuelSessionManager;
import com.trunksbomb.minetriad.game.MoveResult;
import com.trunksbomb.minetriad.item.CardItem;
import com.trunksbomb.minetriad.registry.TriadItems;

import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.ItemInteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BaseEntityBlock;
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.phys.BlockHitResult;

public class DuelTableBlock extends BaseEntityBlock {
    public static final MapCodec<DuelTableBlock> CODEC = simpleCodec(DuelTableBlock::new);
    public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;

    public DuelTableBlock(Properties properties) {
        super(properties);
        registerDefaultState(stateDefinition.any().setValue(FACING, Direction.SOUTH));
    }

    @Override
    protected MapCodec<? extends BaseEntityBlock> codec() {
        return CODEC;
    }

    @Override
    protected ItemInteractionResult useItemOn(ItemStack stack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hitResult) {
        if (level.isClientSide) {
            return ItemInteractionResult.SUCCESS;
        }

        try {
            if (hitResult.getDirection() != Direction.UP) {
                player.displayClientMessage(Component.literal("Click the top face of the Duel Table to target a board space.").withStyle(ChatFormatting.YELLOW), false);
                return ItemInteractionResult.CONSUME;
            }
            Direction tableFacing = state.getValue(FACING);

            DuelTableBlockEntity table = getTableEntity(level, pos);
            if (table == null) {
                player.displayClientMessage(Component.literal("Duel table storage is unavailable.").withStyle(ChatFormatting.RED), false);
                return ItemInteractionResult.CONSUME;
            }

            DuelSession session = DuelSessionManager.get(player);
            if (session == null) {
                boolean aiVsAi = stack.isEmpty();
                try {
                    session = DuelSessionManager.start(player, pos, aiVsAi);
                } catch (IllegalStateException exception) {
                    player.displayClientMessage(Component.literal("You need 5 Triad Cards in your inventory to start a duel.").withStyle(ChatFormatting.YELLOW), false);
                    return ItemInteractionResult.CONSUME;
                }
                table.clearBoard();
                table.setParticipants(session.playerParticipantId(), session.opponentParticipantId());
                if (aiVsAi) {
                    player.displayClientMessage(Component.literal("AI vs AI duel started. Empty-hand click on a Duel Table launches an autoplay match.").withStyle(ChatFormatting.GOLD), false);
                    if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer) {
                        DuelTableAnimationResolver.startAiTurn(table, session, serverPlayer);
                    }
                } else {
                    player.displayClientMessage(session.startMessage().copy().withStyle(ChatFormatting.GOLD), false);
                    player.displayClientMessage(session.handSummary(), false);
                }
                return ItemInteractionResult.CONSUME;
            }

            if (session.isInOverview()) {
                completeOverview(level, pos, player, session);
                return ItemInteractionResult.CONSUME;
            }

            if (table.hasActiveAnimation() || session.isAnimating()) {
                player.displayClientMessage(Component.literal("Wait for the current card animation to finish.").withStyle(ChatFormatting.YELLOW), false);
                return ItemInteractionResult.CONSUME;
            }

            if (!stack.is(TriadItems.TRIAD_CARD.get())) {
                player.displayClientMessage(Component.literal("Hold a Triad Card from your duel hand to play your turn.").withStyle(ChatFormatting.YELLOW), false);
                player.displayClientMessage(session.handSummary(), false);
                return ItemInteractionResult.CONSUME;
            }

            CardStackData cardData = stack.get(com.trunksbomb.minetriad.registry.TriadDataComponents.CARD_DATA);
            if (cardData == null || CardStackData.EMPTY.equals(cardData)) {
                player.displayClientMessage(Component.literal("That card stack has no assigned card data.").withStyle(ChatFormatting.RED), false);
                return ItemInteractionResult.CONSUME;
            }

            MoveResult playerMove = session.playPlayerCard(cardData.cardId(), hitResult, player.getAbilities().instabuild, tableFacing);
            if (!playerMove.valid()) {
                player.displayClientMessage(Component.literal("Move rejected: " + playerMove.errorMessage()).withStyle(ChatFormatting.RED), false);
                player.displayClientMessage(session.boardSummary().copy().withStyle(ChatFormatting.DARK_GRAY), false);
                player.displayClientMessage(session.handSummary(), false);
                return ItemInteractionResult.CONSUME;
            }

            if (!placeBoardCard(table, playerMove, DuelTableBlockEntity.OWNER_FIRST)) {
                player.displayClientMessage(Component.literal("That board slot is already occupied in the table inventory.").withStyle(ChatFormatting.RED), false);
                clearAndRefund(level, pos, player, true);
                return ItemInteractionResult.CONSUME;
            }

            if (!player.getAbilities().instabuild) {
                stack.consume(1, player);
            }

            session.beginPlayerAnimation();
            table.startMoveAnimation(playerMove, DuelTableBlockEntity.OWNER_FIRST);
            player.displayClientMessage(Component.literal("You play " + playerMove.playedCardName() + "."), false);
            sendBattleLog(player, playerMove, ChatFormatting.DARK_AQUA);
            return ItemInteractionResult.CONSUME;
        } catch (Exception exception) {
            MineTriad.LOGGER.error("Duel table interaction failed", exception);
            player.displayClientMessage(Component.literal("Duel error: " + exception.getClass().getSimpleName() + ": " + exception.getMessage())
                    .withStyle(ChatFormatting.RED), false);
            clearAndRefund(level, pos, player, true);
            return ItemInteractionResult.CONSUME;
        }
    }

    @Override
    protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) {
        return useItemOn(ItemStack.EMPTY, state, level, pos, player, InteractionHand.MAIN_HAND, hitResult).result();
    }

    @Override
    public BlockState playerWillDestroy(Level level, BlockPos pos, BlockState state, Player player) {
        return super.playerWillDestroy(level, pos, state, player);
    }

    @Override
    protected float getDestroyProgress(BlockState state, Player player, net.minecraft.world.level.BlockGetter level, BlockPos pos) {
        if (!player.getAbilities().instabuild && DuelSessionManager.hasActiveAt(pos)) {
            return 0.0F;
        }
        return super.getDestroyProgress(state, player, level, pos);
    }

    @Override
    protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
        if (state.getBlock() != newState.getBlock()) {
            for (var cardId : DuelSessionManager.endAndCollectRemainingAt(pos)) {
                Block.popResource(level, pos, CardItem.createCardStack(cardId, TriadItems.TRIAD_CARD.get()));
            }
            DuelTableBlockEntity table = getTableEntity(level, pos);
            if (table != null) {
                table.dropBoardCards(level, pos);
            }
        }
        super.onRemove(state, level, pos, newState, isMoving);
    }

    @Override
    public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
        return new DuelTableBlockEntity(pos, state);
    }

    @Override
    public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> blockEntityType) {
        return createTickerHelper(blockEntityType, com.trunksbomb.minetriad.registry.TriadBlockEntities.DUEL_TABLE.get(), DuelTableBlockEntity::tick);
    }

    @Override
    protected RenderShape getRenderShape(BlockState state) {
        return RenderShape.MODEL;
    }

    @Override
    protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
        builder.add(FACING);
    }

    @Override
    public BlockState getStateForPlacement(BlockPlaceContext context) {
        return defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite());
    }

    private static boolean placeBoardCard(DuelTableBlockEntity table, MoveResult moveResult, int owner) {
        if (moveResult.playedCardId() == null || moveResult.playedCell() == null) {
            return false;
        }
        return table.setCard(moveResult.playedCell().index(), CardItem.createCardStack(moveResult.playedCardId(), TriadItems.TRIAD_CARD.get()), owner);
    }

    private static void sendBattleLog(Player player, MoveResult moveResult, ChatFormatting color) {
        for (String line : moveResult.battleLog()) {
            player.displayClientMessage(Component.literal(line).withStyle(color), false);
        }
    }

    private static DuelTableBlockEntity getTableEntity(Level level, BlockPos pos) {
        BlockEntity blockEntity = level.getBlockEntity(pos);
        return blockEntity instanceof DuelTableBlockEntity duelTableBlockEntity ? duelTableBlockEntity : null;
    }

    private static void clearAndRefund(Level level, BlockPos pos, Player player, boolean refundFullHand) {
        DuelTableBlockEntity table = getTableEntity(level, pos);
        if (table != null) {
            table.clearBoard();
        }
        DuelSessionManager.end(player, refundFullHand);
    }

    private static void completeOverview(Level level, BlockPos pos, Player player, DuelSession session) {
        DuelTableBlockEntity table = getTableEntity(level, pos);
        if (table != null) {
            session.beginClosingAnimation();
            table.startClearWaveAnimation();
        }
    }
}
