import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.PrintStream;

public class TaxAppTester {

    public static void main(String[] args) {
        System.out.println("==================================================");
        System.out.println("          RUNNING INCOME TAX PROJECT TESTS       ");
        System.out.println("==================================================");

        int totalTests = 5;
        int passedTests = 0;

        if (testSingleTaxBackend()) passedTests++;
        if (testMarriedTaxBackend()) passedTests++;
        if (testDeductionFloorBackend()) passedTests++;
        if (testConsoleFrontendOutputSingle()) passedTests++;
        if (testConsoleFrontendOutputMarried()) passedTests++;

        System.out.println("==================================================");
        System.out.println("TESTING SUMMARY: " + passedTests + " / " + totalTests + " PASSED");
        System.out.println("==================================================");
        
        if (passedTests < totalTests) {
            System.exit(1);
        }
    }

    private static boolean testSingleTaxBackend() {
        System.out.print("Test 1 [Backend Single Tax Math]: ");
        try {
            double actualTax = TaxCalculator.calculateSingleTax(66100.0);
            if (Math.abs(actualTax - 5752.00) < 0.01) {
                System.out.println("PASSED");
                return true;
            } else {
                System.out.println("FAILED! Expected $5752.00 but got $" + actualTax);
            }
        } catch (Exception e) {
            System.out.println("FAILED with exception: " + e.getMessage());
        }
        return false;
    }

    private static boolean testMarriedTaxBackend() {
        System.out.print("Test 2 [Backend Married Tax Math]: ");
        try {
            double actualTax = TaxCalculator.calculateMarriedTax(132200.0);
            if (Math.abs(actualTax - 11504.00) < 0.01) {
                System.out.println("PASSED");
                return true;
            } else {
                System.out.println("FAILED! Expected $11504.00 but got $" + actualTax);
            }
        } catch (Exception e) {
            System.out.println("FAILED with exception: " + e.getMessage());
        }
        return false;
    }

    private static boolean testDeductionFloorBackend() {
        System.out.print("Test 3 [Backend Deduction Floor]: ");
        try {
            double actualTax = TaxCalculator.calculateSingleTax(12000.0); 
            if (actualTax == 0.0) {
                System.out.println("PASSED");
                return true;
            } else {
                System.out.println("FAILED! Expected $0.00 tax but got $" + actualTax);
            }
        } catch (Exception e) {
            System.out.println("FAILED with exception: " + e.getMessage());
        }
        return false;
    }

    private static boolean testConsoleFrontendOutputSingle() {
        System.out.print("Test 4 [Frontend Single Output Format]: ");
        
        InputStream originalIn = System.in;
        PrintStream originalOut = System.out;
        String simulatedInput = "  siNGle  \n100000\n";
        
        String[] expectedSnippets = {
            "Filing Profile:      single",
            "Gross Income:        $100000.0",
            "Standard Deduction: -$16100.0",
            "Taxable Income:      $83900.0",
            "Total Tax Owed:      $13170.0",
            "Effective Tax Rate:  13.17%"
        };

        try {
            ByteArrayInputStream testIn = new ByteArrayInputStream(simulatedInput.getBytes());
            System.setIn(testIn);

            ByteArrayOutputStream testOut = new ByteArrayOutputStream();
            System.setOut(new PrintStream(testOut));

            TaxConsoleApp.main(new String[0]);

            System.setIn(originalIn);
            System.setOut(originalOut);

            String consoleOutput = testOut.toString();

            for (String snippet : expectedSnippets) {
                if (!consoleOutput.contains(snippet)) {
                    System.out.println("FAILED!");
                    printDiagnosticFailure(simulatedInput, snippet, consoleOutput);
                    return false;
                }
            }

            System.out.println("PASSED");
            return true;

        } catch (Exception e) {
            System.setIn(originalIn);
            System.setOut(originalOut);
            System.out.println("FAILED with crash exception: " + e.getMessage());
        }
        return false;
    }

    private static boolean testConsoleFrontendOutputMarried() {
        System.out.print("Test 5 [Frontend Married Rounding Format]: ");
        
        InputStream originalIn = System.in;
        PrintStream originalOut = System.out;
        String simulatedInput = "married\n50000.556\n";
        
        String[] expectedSnippets = {
            "Filing Profile:      married",
            "Gross Income:        $50000.56",
            "Standard Deduction: -$32200.0",
            "Taxable Income:      $17800.56",
            "Total Tax Owed:      $1780.06",
            "Effective Tax Rate:  3.56%"
        };

        try {
            ByteArrayInputStream testIn = new ByteArrayInputStream(simulatedInput.getBytes());
            System.setIn(testIn);

            ByteArrayOutputStream testOut = new ByteArrayOutputStream();
            System.setOut(new PrintStream(testOut));

            TaxConsoleApp.main(new String[0]);

            System.setIn(originalIn);
            System.setOut(originalOut);

            String consoleOutput = testOut.toString();

            for (String snippet : expectedSnippets) {
                if (!consoleOutput.contains(snippet)) {
                    System.out.println("FAILED!");
                    printDiagnosticFailure(simulatedInput, snippet, consoleOutput);
                    return false;
                }
            }

            System.out.println("PASSED");
            return true;

        } catch (Exception e) {
            System.setIn(originalIn);
            System.setOut(originalOut);
            System.out.println("FAILED with crash exception: " + e.getMessage());
        }
        return false;
    }

    private static void printDiagnosticFailure(String inputs, String expected, String actual) {
        System.out.println("----------------------------------------------------------------");
        System.out.println("[NOTE: Testing redirects standard streams. Typed keystrokes are hidden]");
        System.out.println("SIMULATED USER ENTRY KEYS:\n" + inputs.trim());
        System.out.println("\nEXPECTED TEXT LINE EXPECTATION:\n" + expected);
        System.out.println("\nYOUR ACTUAL TERMINAL OUTPUT PAYLOAD:\n" + actual.trim());
        System.out.println("----------------------------------------------------------------");
    }
}