import unittest
from gst_validator_india import (
    validate_gstin, 
    validate_invoice, 
    clean_ocr_gstin, 
    extract_gstin_from_text
)

class TestGSTValidator(unittest.TestCase):
    """
    Standard test suite for gst_validator_india.
    Run this using: python3 -m unittest tests/test_gst_validator.py
    """

    def test_valid_corporate_gstin(self):
        """Test with known valid corporate GSTINs (Mahindra & Mahindra)."""
        # Mahindra & Mahindra Ltd - Maharashtra
        mahindra_gstin = "27AAACM3025E1ZZ"
        result = validate_gstin(mahindra_gstin)
        
        self.assertTrue(result['valid'], f"Failed to validate Mahindra GSTIN: {result.get('errors')}")
        self.assertEqual(result['state'], "Maharashtra")
        self.assertEqual(result['entity_type'], "Company")
        self.assertEqual(result['pan'], "AAACM3025E")

    def test_invalid_checksum(self):
        """Test that a GSTIN with an incorrect check digit is rejected."""
        # Changing the last 'Z' to '1' should fail the checksum
        invalid_gstin = "27AAACM3025E1Z1"
        result = validate_gstin(invalid_gstin)
        self.assertFalse(result['valid'])
        self.assertIn("Invalid Format or Checksum", result['errors'])

    def test_ocr_cleaning_logic(self):
        """Test the context-aware OCR repair (O vs 0)."""
        # Dirty GSTIN: 'O' in state code (index 1) and 'I' in entity code (index 11)
        dirty = "2OAAACM3025EIZ5" 
        cleaned = clean_ocr_gstin(dirty)
        
        # Expectation: 
        # index 1: 'O' -> '0' (Numeric required)
        # index 11: 'I' -> '1' (Numeric required for entity code)
        self.assertEqual(cleaned, "20AAACM3025E1Z5")

    def test_intra_state_invoice(self):
        """Test tax validation for Intra-state (Local) supply."""
        invoice_data = {
            "supplier_gstin": "27AAACM3025E1ZZ", # Supplier: Maharashtra (Mahindra)
            "buyer_gstin": "27AABCB2115P1ZP",    # Buyer: Maharashtra (Valid: Business Standard)
            "place_of_supply": "27",
            "tax_amounts": {
                "cgst": 50.0,
                "sgst": 50.0,
                "igst": 0.0
            }
        }
        report = validate_invoice(invoice_data)
        
        # If valid is False, print errors to help debugging
        if not report['valid']:
            print(f"\n[Intra-State Fail] Errors: {report.get('errors')}")

        self.assertTrue(report['valid'])
        self.assertEqual(report['transaction_type'], "INTRA_STATE")

    def test_inter_state_tax_mismatch(self):
        """Test that Inter-state supply fails if CGST/SGST is charged instead of IGST."""
        invoice_data = {
            "supplier_gstin": "27AAACM3025E1ZZ", # Supplier: Maharashtra
            "buyer_gstin": "07AABCB2115P1ZR",    # Buyer: Delhi (Valid: Business Standard)
            "place_of_supply": "07",
            "tax_amounts": {
                "cgst": 50.0, # Error: Should be 0 for Inter-state
                "sgst": 50.0, # Error: Should be 0 for Inter-state
                "igst": 0.0   # Error: Should be 100.0
            }
        }
        report = validate_invoice(invoice_data)
        
        # We expect this to fail validation, but specifically due to "Tax Mismatch"
        self.assertFalse(report['valid'])
        
        # Check if we got the expected Tax Mismatch error
        has_tax_error = any("Tax Mismatch" in e for e in report['errors'])
        if not has_tax_error:
            print(f"\n[Inter-State Fail] Unexpected errors: {report['errors']}")
            
        self.assertTrue(has_tax_error)

    def test_bulk_extraction_from_text(self):
        """Test finding GSTINs in a messy text block."""
        # UPDATED: The second GSTIN is now a valid Delhi GSTIN. 
        # If the GSTIN is invalid (bad checksum), the extractor ignores it.
        text_blob = """
        INVOICE DETAILS
        Supplier: Mahindra & Mahindra | GST: 27AAACM3025E1ZZ
        Recipient: Valid Corp Delhi   | GSTIN: 07AABCB2115P1ZR
        """
        found = extract_gstin_from_text(text_blob)
        self.assertEqual(len(found), 2, f"Expected 2 GSTINs, found: {found}")
        self.assertIn("27AAACM3025E1ZZ", found)
        self.assertIn("07AABCB2115P1ZR", found)

if __name__ == '__main__':
    unittest.main()