package com.trunksbomb.minetriad.game;

import net.minecraft.core.Direction;
import net.minecraft.world.phys.BlockHitResult;

public final class BoardLocalSpace {
    private BoardLocalSpace() {
    }

    public static BoardCell cellForHit(BlockHitResult hitResult, Direction boardFacing) {
        double localX = hitResult.getLocation().x - hitResult.getBlockPos().getX();
        double localZ = hitResult.getLocation().z - hitResult.getBlockPos().getZ();
        double rowProgress = projectProgress(localX, localZ, boardFacing);
        double columnProgress = projectProgress(localX, localZ, rightDirection(boardFacing));
        return new BoardCell(progressToIndex(rowProgress), progressToIndex(columnProgress));
    }

    public static SlotCenter slotCenter(BoardCell cell, Direction boardFacing) {
        float rowProgress = (cell.row() + 0.5F) / BoardCell.SIZE;
        float columnProgress = (cell.column() + 0.5F) / BoardCell.SIZE;
        HorizontalVector bottomVector = vectorFor(boardFacing);
        HorizontalVector rightVector = vectorFor(rightDirection(boardFacing));
        float x = 0.5F + bottomVector.x() * (rowProgress - 0.5F) + rightVector.x() * (columnProgress - 0.5F);
        float z = 0.5F + bottomVector.z() * (rowProgress - 0.5F) + rightVector.z() * (columnProgress - 0.5F);
        return new SlotCenter(x, z);
    }

    public static float cardYawDegrees(Direction boardFacing) {
        Direction topDirection = boardFacing.getOpposite();
        return switch (topDirection) {
            case SOUTH -> 180.0F;
            case NORTH -> 0.0F;
            case EAST -> -90.0F;
            case WEST -> 90.0F;
            default -> 0.0F;
        };
    }

    private static double projectProgress(double localX, double localZ, Direction direction) {
        HorizontalVector vector = vectorFor(direction);
        double offsetX = localX - 0.5D;
        double offsetZ = localZ - 0.5D;
        return 0.5D + (offsetX * vector.x()) + (offsetZ * vector.z());
    }

    private static int progressToIndex(double progress) {
        return Math.min(BoardCell.SIZE - 1, Math.max(0, (int) Math.floor(progress * BoardCell.SIZE)));
    }

    private static Direction rightDirection(Direction boardFacing) {
        return boardFacing.getOpposite().getClockWise();
    }

    private static HorizontalVector vectorFor(Direction direction) {
        return switch (direction) {
            case NORTH -> new HorizontalVector(0.0F, -1.0F);
            case SOUTH -> new HorizontalVector(0.0F, 1.0F);
            case EAST -> new HorizontalVector(1.0F, 0.0F);
            case WEST -> new HorizontalVector(-1.0F, 0.0F);
            default -> throw new IllegalArgumentException("Only horizontal facings are supported");
        };
    }

    private record HorizontalVector(float x, float z) {
    }

    public record SlotCenter(float x, float z) {
    }
}
