package com.tiedup.remake.v2.furniture;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

/**
 * Tests for the pure-logic authorization core in {@link FurnitureAuthPredicate}.
 *
 * <p>These tests pin down the truth tables for the lock and force-mount gates
 * without touching any Minecraft API. The MC-aware wrappers ({@code canLockUnlock},
 * {@code canForceMount}) extract booleans from live entities and delegate here,
 * so full-stack validation is manual (in-game).</p>
 *
 * <p>The 2026-04-17 audit documented three divergent auth paths (BUG-002, BUG-003)
 * that this predicate now unifies. If anyone re-introduces the drift, the
 * isAuthorizedForLock / isAuthorizedForForceMount methods will catch it here.</p>
 */
class FurnitureAuthPredicateTest {

    @Nested
    @DisplayName("isAuthorizedForLock — AND of 4 gates")
    class LockAuthorization {

        @Test
        @DisplayName("all four gates true → authorized")
        void allTrue() {
            assertTrue(
                FurnitureAuthPredicate.isAuthorizedForLock(
                    true,
                    true,
                    true,
                    true
                )
            );
        }

        @Test
        @DisplayName("missing master key → denied")
        void missingKey() {
            assertFalse(
                FurnitureAuthPredicate.isAuthorizedForLock(
                    false,
                    true,
                    true,
                    true
                )
            );
        }

        @Test
        @DisplayName("seat not lockable → denied")
        void seatNotLockable() {
            assertFalse(
                FurnitureAuthPredicate.isAuthorizedForLock(
                    true,
                    false,
                    true,
                    true
                )
            );
        }

        @Test
        @DisplayName("seat not occupied → denied")
        void seatNotOccupied() {
            assertFalse(
                FurnitureAuthPredicate.isAuthorizedForLock(
                    true,
                    true,
                    false,
                    true
                )
            );
        }

        @Test
        @DisplayName("occupant has no collar (or sender not owner) → denied")
        void noOwnedCollar() {
            assertFalse(
                FurnitureAuthPredicate.isAuthorizedForLock(
                    true,
                    true,
                    true,
                    false
                )
            );
        }

        @Test
        @DisplayName("all gates false → denied")
        void allFalse() {
            assertFalse(
                FurnitureAuthPredicate.isAuthorizedForLock(
                    false,
                    false,
                    false,
                    false
                )
            );
        }
    }

    @Nested
    @DisplayName("isAuthorizedForForceMount — AND of 5 gates")
    class ForceMountAuthorization {

        @Test
        @DisplayName("all five gates true → authorized")
        void allTrue() {
            assertTrue(
                FurnitureAuthPredicate.isAuthorizedForForceMount(
                    true,
                    true,
                    true,
                    true,
                    true
                )
            );
        }

        @Test
        @DisplayName("captive not alive → denied")
        void captiveDead() {
            assertFalse(
                FurnitureAuthPredicate.isAuthorizedForForceMount(
                    false,
                    true,
                    true,
                    true,
                    true
                )
            );
        }

        @Test
        @DisplayName("captive out of range → denied")
        void captiveOutOfRange() {
            assertFalse(
                FurnitureAuthPredicate.isAuthorizedForForceMount(
                    true,
                    false,
                    true,
                    true,
                    true
                )
            );
        }

        @Test
        @DisplayName("no owned collar → denied")
        void noOwnedCollar() {
            assertFalse(
                FurnitureAuthPredicate.isAuthorizedForForceMount(
                    true,
                    true,
                    false,
                    true,
                    true
                )
            );
        }

        @Test
        @DisplayName("captive not tied up (leashed) → denied (audit BUG-003)")
        void notTiedUp() {
            // This is the exact regression guard for audit BUG-003: before the
            // fix, the packet path did NOT check isTiedUp, so any collar-owning
            // captor could force-mount a captive that had never been leashed.
            assertFalse(
                FurnitureAuthPredicate.isAuthorizedForForceMount(
                    true,
                    true,
                    true,
                    false,
                    true
                )
            );
        }

        @Test
        @DisplayName("captive already passenger of another entity → denied (audit BUG-003)")
        void alreadyPassenger() {
            // BUG-003 regression guard: before the fix, the packet path used
            // startRiding(force=true) which would break prior mounts silently.
            assertFalse(
                FurnitureAuthPredicate.isAuthorizedForForceMount(
                    true,
                    true,
                    true,
                    true,
                    false
                )
            );
        }

        @Test
        @DisplayName("all gates false → denied")
        void allFalse() {
            assertFalse(
                FurnitureAuthPredicate.isAuthorizedForForceMount(
                    false,
                    false,
                    false,
                    false,
                    false
                )
            );
        }
    }
}
