package com.pandoli365.bibimbap.jam;

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

import com.pandoli365.bibimbap.data.JamData;
import java.time.OffsetDateTime;
import org.junit.jupiter.api.Test;

class JamLifecycleTest {

    private final JamLifecycle lifecycle = new JamLifecycle();

    @Test
    void allowedTransitionsAreAccepted() {
        assertTrue(lifecycle.isAllowed(JamStatus.RECRUIT, JamStatus.DEV));
        assertTrue(lifecycle.isAllowed(JamStatus.DEV, JamStatus.EVAL));
        assertTrue(lifecycle.isAllowed(JamStatus.DEV, JamStatus.RECRUIT));
        assertTrue(lifecycle.isAllowed(JamStatus.EVAL, JamStatus.CLOSED));
        assertTrue(lifecycle.isAllowed(JamStatus.EVAL, JamStatus.DEV));
    }

    @Test
    void disallowedTransitionsAreRejected() {
        assertFalse(lifecycle.isAllowed(JamStatus.RECRUIT, JamStatus.EVAL));
        assertFalse(lifecycle.isAllowed(JamStatus.RECRUIT, JamStatus.CLOSED));
        assertFalse(lifecycle.isAllowed(JamStatus.DEV, JamStatus.CLOSED));
        assertFalse(lifecycle.isAllowed(JamStatus.CLOSED, JamStatus.RECRUIT));
        assertFalse(lifecycle.isAllowed(JamStatus.CLOSED, JamStatus.DEV));
        assertFalse(lifecycle.isAllowed(JamStatus.CLOSED, JamStatus.EVAL));
        assertFalse(lifecycle.isAllowed(JamStatus.EVAL, JamStatus.RECRUIT));
    }

    @Test
    void sameStateTransitionsAreRejected() {
        assertFalse(lifecycle.isAllowed(JamStatus.RECRUIT, JamStatus.RECRUIT));
        assertFalse(lifecycle.isAllowed(JamStatus.DEV, JamStatus.DEV));
        assertFalse(lifecycle.isAllowed(JamStatus.EVAL, JamStatus.EVAL));
        assertFalse(lifecycle.isAllowed(JamStatus.CLOSED, JamStatus.CLOSED));
    }

    @Test
    void nullArgumentsAreRejected() {
        assertFalse(lifecycle.isAllowed(null, JamStatus.DEV));
        assertFalse(lifecycle.isAllowed(JamStatus.RECRUIT, null));
    }

    @Test
    void periodReadyEnforcesEvalStartForEval() {
        OffsetDateTime now = OffsetDateTime.now();
        assertTrue(lifecycle.isPeriodReady(JamStatus.EVAL, now, null));
        assertFalse(lifecycle.isPeriodReady(JamStatus.EVAL, null, null));
    }

    @Test
    void periodReadyEnforcesEvalEndForClosed() {
        OffsetDateTime now = OffsetDateTime.now();
        assertTrue(lifecycle.isPeriodReady(JamStatus.CLOSED, null, now));
        assertFalse(lifecycle.isPeriodReady(JamStatus.CLOSED, null, null));
    }

    @Test
    void periodReadyAlwaysTrueForRecruitAndDev() {
        assertTrue(lifecycle.isPeriodReady(JamStatus.RECRUIT, null, null));
        assertTrue(lifecycle.isPeriodReady(JamStatus.DEV, null, null));
    }

    @Test
    void periodReadyOverloadDelegatesToJamGetters() {
        OffsetDateTime now = OffsetDateTime.now();

        JamData evalReady = new JamData();
        evalReady.setEvalStartAt(now);
        assertTrue(lifecycle.isPeriodReady(JamStatus.EVAL, evalReady));

        JamData evalMissing = new JamData();
        assertFalse(lifecycle.isPeriodReady(JamStatus.EVAL, evalMissing));

        JamData closedReady = new JamData();
        closedReady.setEvalEndAt(now);
        assertTrue(lifecycle.isPeriodReady(JamStatus.CLOSED, closedReady));

        JamData closedMissing = new JamData();
        assertFalse(lifecycle.isPeriodReady(JamStatus.CLOSED, closedMissing));
    }
}
