import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;

/**
 * Test class for the Paycheck program.
 *
 * @author Sarah Heckman
 * @author Jessica Young Schmidt
 */
public class PaycheckTest {

    /**
     * Test the Paycheck.getPayRate() method.
     */
    @Test
    public void testGetPayRate() {
        // Test level 1
        assertEquals(Paycheck.LEVEL_1_PAY_RATE,
                Paycheck.getPayRate(Paycheck.LEVEL_1),
                "Paycheck.getPayRate(Paycheck.LEVEL_1)");

        // Test level 2
        assertEquals(Paycheck.LEVEL_2_PAY_RATE,
                Paycheck.getPayRate(Paycheck.LEVEL_2),
                "Paycheck.getPayRate(Paycheck.LEVEL_2)");

        // Test level 3
        assertEquals(Paycheck.LEVEL_3_PAY_RATE,
                Paycheck.getPayRate(Paycheck.LEVEL_3),
                "Paycheck.getPayRate(Paycheck.LEVEL_3)");

        // Test level 0 - invalid lower boundary
        assertEquals(Paycheck.INVALID, Paycheck.getPayRate(0),
                "Paycheck.getPayRate(0)");

        // Test level 4 - invalid upper boundary
        assertEquals(Paycheck.INVALID, Paycheck.getPayRate(4),
                "Paycheck.getPayRate(4)");
    }

    /**
     * Test the Paycheck.calculateRegularPay() method.
     */
    @Test
    public void testCalculateRegularPay() {
        // Only testing valid values for the moment.

        // Less than 40 hours
        // Regular Level 1 36 hours
        assertEquals(68400,
                Paycheck.calculateRegularPay(Paycheck.LEVEL_1_PAY_RATE, 36),
                "Paycheck.calculateRegularPay(Paycheck.LEVEL_1_PAY_RATE, 36)");

        // Regular Level 2 36 hours
        assertEquals(81000,
                Paycheck.calculateRegularPay(Paycheck.LEVEL_2_PAY_RATE, 36),
                "Paycheck.calculateRegularPay(Paycheck.LEVEL_2_PAY_RATE, 36)");

        // Regular Level 3 36 hours
        assertEquals(92700,
                Paycheck.calculateRegularPay(Paycheck.LEVEL_3_PAY_RATE, 36),
                "Paycheck.calculateRegularPay(Paycheck.LEVEL_3_PAY_RATE, 36)");

        // Over 40 hours
        // Regular Level 1 46 hours
        assertEquals(76000,
                Paycheck.calculateRegularPay(Paycheck.LEVEL_1_PAY_RATE, 46),
                "Paycheck.calculateRegularPay(Paycheck.LEVEL_1_PAY_RATE, 46)");

        // Regular Level 2 46 hours
        assertEquals(90000,
                Paycheck.calculateRegularPay(Paycheck.LEVEL_2_PAY_RATE, 46),
                "Paycheck.calculateRegularPay(Paycheck.LEVEL_2_PAY_RATE, 46)");

        // Regular Level 3 46 hours
        assertEquals(103000,
                Paycheck.calculateRegularPay(Paycheck.LEVEL_3_PAY_RATE, 46),
                "Paycheck.calculateRegularPay(Paycheck.LEVEL_3_PAY_RATE, 46)");

        // Fractional hours less than 40
        // Regular Level 1 36.5 hours
        assertEquals(69350,
                Paycheck.calculateRegularPay(Paycheck.LEVEL_1_PAY_RATE, 36.5),
                "Paycheck.calculateRegularPay(Paycheck.LEVEL_1_PAY_RATE, 36.5)");

        // Regular Level 2 36.5 hours
        assertEquals(82125,
                Paycheck.calculateRegularPay(Paycheck.LEVEL_2_PAY_RATE, 36.5),
                "Paycheck.calculateRegularPay(Paycheck.LEVEL_2_PAY_RATE, 36.5)");

        // Regular Level 3 36.5 hours
        assertEquals(93987,
                Paycheck.calculateRegularPay(Paycheck.LEVEL_3_PAY_RATE, 36.5),
                "Paycheck.calculateRegularPay(Paycheck.LEVEL_3_PAY_RATE, 36.5)");

        // Test a payrate other than a given constant Regular
        assertEquals(34950, Paycheck.calculateRegularPay(1376, 25.4),
                "Paycheck.calculateRegularPay(1376, 25.4)");

        // Testing boundary
        // Less than 40 hours
        // Regular Level 1 39 hours
        assertEquals(74100,
                Paycheck.calculateRegularPay(Paycheck.LEVEL_1_PAY_RATE, 39),
                "Paycheck.calculateRegularPay(Paycheck.LEVEL_1_PAY_RATE, 39)");

        // Regular Level 2 39 hours
        assertEquals(87750,
                Paycheck.calculateRegularPay(Paycheck.LEVEL_2_PAY_RATE, 39),
                "Paycheck.calculateRegularPay(Paycheck.LEVEL_2_PAY_RATE, 39)");

        // Regular Level 3 39 hours
        assertEquals(100425,
                Paycheck.calculateRegularPay(Paycheck.LEVEL_3_PAY_RATE, 39),
                "Paycheck.calculateRegularPay(Paycheck.LEVEL_3_PAY_RATE, 39)");

        // Regular Level 1 40 hours
        assertEquals(76000,
                Paycheck.calculateRegularPay(Paycheck.LEVEL_1_PAY_RATE, 40),
                "Paycheck.calculateRegularPay(Paycheck.LEVEL_1_PAY_RATE, 40)");

        // Regular Level 2 40 hours
        assertEquals(90000,
                Paycheck.calculateRegularPay(Paycheck.LEVEL_2_PAY_RATE, 40),
                "Paycheck.calculateRegularPay(Paycheck.LEVEL_2_PAY_RATE, 40)");

        // Regular Level 3 40 hours
        assertEquals(103000,
                Paycheck.calculateRegularPay(Paycheck.LEVEL_3_PAY_RATE, 40),
                "Paycheck.calculateRegularPay(Paycheck.LEVEL_3_PAY_RATE, 40)");

        // Over 40 hours
        // Regular Level 1 41 hours
        assertEquals(76000,
                Paycheck.calculateRegularPay(Paycheck.LEVEL_1_PAY_RATE, 41),
                "Paycheck.calculateRegularPay(Paycheck.LEVEL_1_PAY_RATE, 41)");

        // Regular Level 2 41 hours
        assertEquals(90000,
                Paycheck.calculateRegularPay(Paycheck.LEVEL_2_PAY_RATE, 41),
                "Paycheck.calculateRegularPay(Paycheck.LEVEL_2_PAY_RATE, 41)");

        // Regular Level 3 41 hours
        assertEquals(103000,
                Paycheck.calculateRegularPay(Paycheck.LEVEL_3_PAY_RATE, 41),
                "Paycheck.calculateRegularPay(Paycheck.LEVEL_3_PAY_RATE, 41)");
    }

    /**
     * Test the Paycheck.calculateOvertimePay() method.
     */
    @Test
    public void testCalculateOvertimePay() {
        // Only testing valid values for the moment.

        // Less than 40 hours
        // Overtime Level 1 36 hours
        assertEquals(0,
                Paycheck.calculateOvertimePay(Paycheck.LEVEL_1_PAY_RATE, 36),
                "Paycheck.calculateOvertimePay(Paycheck.LEVEL_1_PAY_RATE, 36)");

        // Overtime Level 2 36 hours
        assertEquals(0,
                Paycheck.calculateOvertimePay(Paycheck.LEVEL_2_PAY_RATE, 36),
                "Paycheck.calculateOvertimePay(Paycheck.LEVEL_2_PAY_RATE, 36)");

        // Overtime Level 3 36 hours
        assertEquals(0,
                Paycheck.calculateOvertimePay(Paycheck.LEVEL_3_PAY_RATE, 36),
                "Paycheck.calculateOvertimePay(Paycheck.LEVEL_3_PAY_RATE, 36)");

        // Over 40 hours
        // Overtime Level 1 46 hours
        assertEquals(17100,
                Paycheck.calculateOvertimePay(Paycheck.LEVEL_1_PAY_RATE, 46),
                "Paycheck.calculateOvertimePay(Paycheck.LEVEL_1_PAY_RATE, 46)");

        // Overtime Level 2 46 hours
        assertEquals(20250,
                Paycheck.calculateOvertimePay(Paycheck.LEVEL_2_PAY_RATE, 46),
                "Paycheck.calculateOvertimePay(Paycheck.LEVEL_2_PAY_RATE, 46)");

        // Overtime Level 3 46 hours
        assertEquals(23172,
                Paycheck.calculateOvertimePay(Paycheck.LEVEL_3_PAY_RATE, 46),
                "Paycheck.calculateOvertimePay(Paycheck.LEVEL_3_PAY_RATE, 46)");

        // Fractional hours less than 40
        // Overtime Level 1 36.5 hours
        assertEquals(0,
                Paycheck.calculateOvertimePay(Paycheck.LEVEL_1_PAY_RATE, 36.5),
                "Paycheck.calculateOvertimePay(Paycheck.LEVEL_1_PAY_RATE, 36.5)");

        // Overtime Level 2 36.5 hours
        assertEquals(0,
                Paycheck.calculateOvertimePay(Paycheck.LEVEL_2_PAY_RATE, 36.5),
                "Paycheck.calculateOvertimePay(Paycheck.LEVEL_2_PAY_RATE, 36.5)");

        // Overtime Level 3 36.5 hours
        assertEquals(0,
                Paycheck.calculateOvertimePay(Paycheck.LEVEL_3_PAY_RATE, 36.5),
                "Paycheck.calculateOvertimePay(Paycheck.LEVEL_3_PAY_RATE, 36.5)");

        // Fractional hours over 40 hours
        // Overtime Level 1 46.5 hours
        assertEquals(18525,
                Paycheck.calculateOvertimePay(Paycheck.LEVEL_1_PAY_RATE, 46.5),
                "Paycheck.calculateOvertimePay(Paycheck.LEVEL_1_PAY_RATE, 46.5)");

        // Overtime Level 2 46.5 hours
        assertEquals(21937,
                Paycheck.calculateOvertimePay(Paycheck.LEVEL_2_PAY_RATE, 46.5),
                "Paycheck.calculateOvertimePay(Paycheck.LEVEL_2_PAY_RATE, 46.5)");

        // Overtime Level 3 46 hours
        assertEquals(

                25103,
                Paycheck.calculateOvertimePay(Paycheck.LEVEL_3_PAY_RATE, 46.5),
                "Paycheck.calculateOvertimePay(Paycheck.LEVEL_3_PAY_RATE, 46.5)");

        // Test a payrate other than a given constant Regular
        assertEquals(14964, Paycheck.calculateOvertimePay(1376, 47.25),
                "Paycheck.calculateOvertimePay(1376, 47.25)");
    }

    /**
     * Test the Paycheck.calculateGrossPay() method.
     */
    @Test
    public void testCalculateGrossPay() {
        // Only testing valid values for the moment.

        // Less than 40 hours
        // Gross Level 1 36 hours
        assertEquals(68400, Paycheck.calculateGrossPay(68400, 0),
                "Paycheck.calculateGrossPay(68400, 0)");

        // Gross Level 2 36 hours
        assertEquals(81000, Paycheck.calculateGrossPay(81000, 0),
                "Paycheck.calculateGrossPay(81000, 0)");

        // Gross Level 3 36 hours
        assertEquals(92700, Paycheck.calculateGrossPay(92700, 0),
                "Paycheck.calculateGrossPay(92700, 0)");

        // Over 40 hours
        // Gross Level 1 46 hours
        assertEquals(93100, Paycheck.calculateGrossPay(76000, 17100),
                "Paycheck.calculateGrossPay(76000, 17100)");

        // Gross Level 2 46 hours
        assertEquals(110250, Paycheck.calculateGrossPay(90000, 20250),
                "Paycheck.calculateGrossPay(90000, 20250)");

        // Gross Level 3 46 hours
        assertEquals(126172, Paycheck.calculateGrossPay(103000, 23172),
                "Paycheck.calculateGrossPay(103000, 23172)");

        // Fractional hours less than 40
        // Gross Level 1 36.5 hours
        assertEquals(69350, Paycheck.calculateGrossPay(69350, 0),
                "Paycheck.calculateGrossPay(69350, 0)");

        // Overtime Level 2 36.5 hours
        assertEquals(82125, Paycheck.calculateGrossPay(82125, 0),
                "Paycheck.calculateGrossPay(82125, 0)");

        // Gross Level 3 36.5 hours
        assertEquals(93987, Paycheck.calculateGrossPay(93987, 0),
                "Paycheck.calculateGrossPay(93987, 0)");

        // Fractional hours over 40 hours
        // Gross Level 1 46.5 hours
        assertEquals(94525, Paycheck.calculateGrossPay(76000, 18525),
                "Paycheck.calculateGrossPay(76000, 18525)");

        // Gross Level 2 46.5 hours
        assertEquals(111937, Paycheck.calculateGrossPay(90000, 21937),
                "Paycheck.calculateGrossPay(90000, 21937)");

        // Gross Level 3 46 hours
        assertEquals(128103, Paycheck.calculateGrossPay(103000, 25103),
                "Paycheck.calculateGrossPay(103000, 25103)");

        // Test a payrate other than a given constant Gross
        assertEquals(49914, Paycheck.calculateGrossPay(34950, 14964),
                "Paycheck.calculateGrossPay(34950, 14964)");
    }

    /**
     * Test the Paycheck.calculateTotalDeductions() method.
     */
    @Test
    public void testCalculateRetirement() {
        // Only testing valid values for the moment.

        // Zero percent retirement
        assertEquals(0, Paycheck.calculateRetirement(92700, 0),
                "Paycheck.calculateRetirement(92700, 0)");

        // One percent retirement
        assertEquals(927, Paycheck.calculateRetirement(92700, 1),
                "Paycheck.calculateRetirement(92700, 1)");

        // Two percent retirement
        assertEquals(1854, Paycheck.calculateRetirement(92700, 2),
                "Paycheck.calculateRetirement(92700, 2)");

        // Three percent retirement
        assertEquals(2781, Paycheck.calculateRetirement(92700, 3),
                "Paycheck.calculateRetirement(92700, 3)");

        // Four percent retirement
        assertEquals(3708, Paycheck.calculateRetirement(92700, 4),
                "Paycheck.calculateRetirement(92700, 4)");

        // Five percent retirement
        assertEquals(4635, Paycheck.calculateRetirement(92700, 5),
                "Paycheck.calculateRetirement(92700, 5)");

        // Six percent retirement
        assertEquals(5562, Paycheck.calculateRetirement(92700, 6),
                "Paycheck.calculateRetirement(92700, 6)");
    }

    /**
     * Test the Paycheck.calculateNetPay() method.
     */
    @Test
    public void testCalculateNetPay() {
        // Only testing valid values for the moment.

        // Calculate net pay with deductions
        assertEquals(86211, Paycheck.calculateNetPay(92700, 6489),
                "Paycheck.calculateNetPay(92700, 6489)");

        // Calculate net pay without deductions
        assertEquals(92700, Paycheck.calculateNetPay(92700, 0),
                "Paycheck.calculateNetPay(92700, 0)");

        // Calculate net pay - negative
        assertEquals(-1100, Paycheck.calculateNetPay(92700, 93800),
                "Paycheck.calculateNetPay(92700, 93800)");
    }

}
