import pytest
from klp import parse_cef


@pytest.mark.parametrize(
    "line, expected",
    [
        # CEF 0.x version with syslog prefix (timestamp and host)
        (
            "Sep 19 08:26:10 host CEF:0|Security|threatmanager|1.0|100|worm successfully stopped|10|src=10.0.0.1 dst=2.1.2.2 spt=1232",
            {
                "timestamp": "Sep 19 08:26:10",
                "host": "host",
                "cefver": "0",
                "vendor": "Security",
                "product": "threatmanager",
                "version": "1.0",
                "eventid": "100",
                "event": "worm successfully stopped",
                "severity": "10",
                "src": "10.0.0.1",
                "dst": "2.1.2.2",
                "spt": "1232",
            },
        ),
        # CEF 1.x version with syslog prefix
        (
            "Sep 29 08:26:10 host CEF:1|Security|threatmanager|1.0|100|worm successfully stopped|10|src=10.0.0.1 dst=2.1.2.2 spt=1232",
            {
                "timestamp": "Sep 29 08:26:10",
                "host": "host",
                "cefver": "1",
                "vendor": "Security",
                "product": "threatmanager",
                "version": "1.0",
                "eventid": "100",
                "event": "worm successfully stopped",
                "severity": "10",
                "src": "10.0.0.1",
                "dst": "2.1.2.2",
                "spt": "1232",
            },
        ),
        # Escaped pipe in header/extension.
        (
            r"Sep 19 08:26:10 host CEF:0|security|threatmanager|1.0|100|detected a \| in message|10|src=10.0.0.1 act=blocked a | dst=1.1.1.1",
            {
                "timestamp": "Sep 19 08:26:10",
                "host": "host",
                "cefver": "0",
                "vendor": "security",
                "product": "threatmanager",
                "version": "1.0",
                "eventid": "100",
                "event": "detected a | in message",
                "severity": "10",
                "src": "10.0.0.1",
                "act": "blocked a |",
                "dst": "1.1.1.1",
            },
        ),
        # Escaped backslash in header/extension.
        (
            "Sep 19 08:26:10 host CEF:0|security|threatmanager|1.0|100|detected a \\\\ in packet|10|src=10.0.0.1 act=blocked a \\\\ dst=1.1.1.1",
            {
                "timestamp": "Sep 19 08:26:10",
                "host": "host",
                "cefver": "0",
                "vendor": "security",
                "product": "threatmanager",
                "version": "1.0",
                "eventid": "100",
                "event": "detected a \\ in packet",
                "severity": "10",
                "src": "10.0.0.1",
                "act": "blocked a \\",
                "dst": "1.1.1.1",
            },
        ),
        # Escaped equals sign in extension.
        (
            "Sep 19 08:26:10 host CEF:0|security|threatmanager|1.0|100|detected a = in message|10|src=10.0.0.1 act=blocked a \\= dst=1.1.1.1",
            {
                "timestamp": "Sep 19 08:26:10",
                "host": "host",
                "cefver": "0",
                "vendor": "security",
                "product": "threatmanager",
                "version": "1.0",
                "eventid": "100",
                "event": "detected a = in message",
                "severity": "10",
                "src": "10.0.0.1",
                "act": "blocked a =",
                "dst": "1.1.1.1",
            },
        ),
        # Multi‐line extension value.
        (
            "Sep 19 08:26:10 host CEF:0|security|threatmanager|1.0|100|Detected a threat. No action needed.|10|src=10.0.0.1 msg=Detected a threat.\n No action needed",
            {
                "timestamp": "Sep 19 08:26:10",
                "host": "host",
                "cefver": "0",
                "vendor": "security",
                "product": "threatmanager",
                "version": "1.0",
                "eventid": "100",
                "event": "Detected a threat. No action needed.",
                "severity": "10",
                "src": "10.0.0.1",
                "msg": "Detected a threat.\n No action needed",
            },
        ),
        # Syslog prefix with timestamp and host, simple extension.
        (
            "Oct 01 10:20:30 server1 CEF:0|Vendor|Product|2.0|200|Some Event|4|key1=value1 key2=value2",
            {
                "timestamp": "Oct 01 10:20:30",
                "host": "server1",
                "cefver": "0",
                "vendor": "Vendor",
                "product": "Product",
                "version": "2.0",
                "eventid": "200",
                "event": "Some Event",
                "severity": "4",
                "key1": "value1",
                "key2": "value2",
            },
        ),
        # No syslog prefix.
        (
            "CEF:1|V|P|1.2|300|Test Event|7|k=v",
            {
                "cefver": "1",
                "vendor": "V",
                "product": "P",
                "version": "1.2",
                "eventid": "300",
                "event": "Test Event",
                "severity": "7",
                "k": "v",
            },
        ),
        # Single-token syslog prefix.
        (
            "server2 CEF:1|V|P|1.2|300|Test Event|7|k=v",
            {
                "host": "server2",
                "cefver": "1",
                "vendor": "V",
                "product": "P",
                "version": "1.2",
                "eventid": "300",
                "event": "Test Event",
                "severity": "7",
                "k": "v",
            },
        ),
        # Leading whitespace with no syslog prefix.
        (
            "   CEF:1|V|P|1.2|300|Test Event|7|k=v",
            {
                "cefver": "1",
                "vendor": "V",
                "product": "P",
                "version": "1.2",
                "eventid": "300",
                "event": "Test Event",
                "severity": "7",
                "k": "v",
            },
        ),
        # Complex log with many extension fields
        (
            r"""CEF:0|Security Corp|WebGuard|2.0|100|Unauthorized Access|8| fileId=2023111500981234 sourceServiceName=webapp.example.net serviceId=2468135 userId=1000567 requestClientApplication=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 datacenter=us-east cs2=true cs2Label=Browser Verification cs3=true cs3Label=Security Check countryCode=US hostname=www.example.net responseCode=403 bytesIn=128 forwardedIP=192.168.1.100 cs1=VERIFIED cs1Label=Auth Status cs4=7b891234-a123-4456-b789-0123456789ab cs4Label=Session ID cs5=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2g3h4i5j6k7l8m9n0 cs5Label=signature processingUnit=WebServer cs6=Chrome cs6Label=browser countryCity=Seattle cs7=47.6062 cs7Label=latitude cs8=122.3321 cs8Label=longitude accountName=TestUser123 siteIdentifier=main-app requestTime=1641234567890 targetUrl=webapp.example.net/admin requestMethod=POST queryString=action\=modify headers=ADMIN_ACCESS application=HTTPS action=BLOCK_REQUEST deviceId=9876543210123456 port=8443 sourceIP=203.0.113.45 protocol=TLSv1.3 AES256-GCM-SHA384 endTime=1641234569999 requestHeaders=[{"User-Agent":"Mozilla/5.0"},{"Authorization":"Bearer abc123"},{"X-Request-ID":"req-987654"}] responseHeaders=[{"Content-Type":"application/json"}] category=4002,3001, permissions=4,2, cs9=Suspicious Activity,Rate Limit Exceeded, cs9Label=Alert Type cs11=,,[{"violation_type":"RATE_LIMIT","threshold":"100/minute"}] cs11Label=Alert Details""",
            {
                "cefver": "0",
                "vendor": "Security Corp",
                "product": "WebGuard",
                "version": "2.0",
                "eventid": "100",
                "event": "Unauthorized Access",
                "severity": "8",
                "fileId": "2023111500981234",
                "sourceServiceName": "webapp.example.net",
                "serviceId": "2468135",
                "userId": "1000567",
                "requestClientApplication": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
                "datacenter": "us-east",
                "cs2": "true",
                "cs2Label": "Browser Verification",
                "cs3": "true",
                "cs3Label": "Security Check",
                "countryCode": "US",
                "hostname": "www.example.net",
                "responseCode": "403",
                "bytesIn": "128",
                "forwardedIP": "192.168.1.100",
                "cs1": "VERIFIED",
                "cs1Label": "Auth Status",
                "cs4": "7b891234-a123-4456-b789-0123456789ab",
                "cs4Label": "Session ID",
                "cs5": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2g3h4i5j6k7l8m9n0",
                "cs5Label": "signature",
                "processingUnit": "WebServer",
                "cs6": "Chrome",
                "cs6Label": "browser",
                "countryCity": "Seattle",
                "cs7": "47.6062",
                "cs7Label": "latitude",
                "cs8": "122.3321",
                "cs8Label": "longitude",
                "accountName": "TestUser123",
                "siteIdentifier": "main-app",
                "requestTime": "1641234567890",
                "targetUrl": "webapp.example.net/admin",
                "requestMethod": "POST",
                "queryString": "action=modify",
                "headers": "ADMIN_ACCESS",
                "application": "HTTPS",
                "action": "BLOCK_REQUEST",
                "deviceId": "9876543210123456",
                "port": "8443",
                "sourceIP": "203.0.113.45",
                "protocol": "TLSv1.3 AES256-GCM-SHA384",
                "endTime": "1641234569999",
                "requestHeaders": '[{"User-Agent":"Mozilla/5.0"},{"Authorization":"Bearer abc123"},{"X-Request-ID":"req-987654"}]',
                "responseHeaders": '[{"Content-Type":"application/json"}]',
                "category": "4002,3001,",
                "permissions": "4,2,",
                "cs9": "Suspicious Activity,Rate Limit Exceeded,",
                "cs9Label": "Alert Type",
                "cs11": ',,[{"violation_type":"RATE_LIMIT","threshold":"100/minute"}]',
                "cs11Label": "Alert Details",
            },
        ),
        # More complex with lots of fields and JSON data in the extension
        (
            """CEF:0|Security Corp|WebGuard|2.0|200|Normal Access|3| sourceServiceName=webapp.example.net serviceId=2468135 userId=1000567 requestClientApplication=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 datacenter=us-east countryCode=US hostname=www.example.net countryCity=Seattle cs7=47.6062 cs7Label=latitude cs8=122.3321 cs8Label=longitude accountName=TestUser123 siteIdentifier=main-app requestTime=1641234567890 targetUrl=webapp.example.net/static/style.css referer=webapp.example.net/home requestMethod=GET responseCode=200 application=HTTPS deviceId=9876543210123456 bytesIn=2048 forwardedIP=192.168.1.100 port=8443 sourceIP=203.0.113.45 protocol=TLSv1.3 AES256-GCM-SHA384 endTime=1641234568999 requestHeaders=[{"Accept":"text/css"},{"Cache-Control":"no-cache"},{"X-Request-ID":"req-987654"}] responseHeaders=[{"Content-Type":"text/css"}]""",
            {
                "cefver": "0",
                "vendor": "Security Corp",
                "product": "WebGuard",
                "version": "2.0",
                "eventid": "200",
                "event": "Normal Access",
                "severity": "3",
                "sourceServiceName": "webapp.example.net",
                "serviceId": "2468135",
                "userId": "1000567",
                "requestClientApplication": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
                "datacenter": "us-east",
                "countryCode": "US",
                "hostname": "www.example.net",
                "countryCity": "Seattle",
                "cs7": "47.6062",
                "cs7Label": "latitude",
                "cs8": "122.3321",
                "cs8Label": "longitude",
                "accountName": "TestUser123",
                "siteIdentifier": "main-app",
                "requestTime": "1641234567890",
                "targetUrl": "webapp.example.net/static/style.css",
                "referer": "webapp.example.net/home",
                "requestMethod": "GET",
                "responseCode": "200",
                "application": "HTTPS",
                "deviceId": "9876543210123456",
                "bytesIn": "2048",
                "forwardedIP": "192.168.1.100",
                "port": "8443",
                "sourceIP": "203.0.113.45",
                "protocol": "TLSv1.3 AES256-GCM-SHA384",
                "endTime": "1641234568999",
                "requestHeaders": '[{"Accept":"text/css"},{"Cache-Control":"no-cache"},{"X-Request-ID":"req-987654"}]',
                "responseHeaders": '[{"Content-Type":"text/css"}]',
            },
        ),
    ],
)
def test_parse_cef(line, expected):
    result = parse_cef(line)
    assert result == expected
