"""
Tests for omnisec.security.SecurityToolkit
"""

import pytest
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

from omnisec.security import SecurityToolkit

sec = SecurityToolkit()


class TestHashing:
    def test_sha256(self):
        h = sec.hash("hello", "sha256")
        assert len(h) == 64
        assert h == sec.hash("hello", "sha256")  # deterministic

    def test_sha512(self):
        h = sec.hash("hello", "sha512")
        assert len(h) == 128

    def test_md5(self):
        h = sec.hash("hello", "md5")
        assert len(h) == 32

    def test_bytes_input(self):
        h = sec.hash(b"hello bytes", "sha256")
        assert len(h) == 64

    def test_invalid_algorithm(self):
        with pytest.raises(ValueError):
            sec.hash("test", "rot13")

    def test_hmac_sign_verify(self):
        sig = sec.hmac_sign("payload", "secret")
        assert sec.hmac_verify("payload", "secret", sig)
        assert not sec.hmac_verify("payload", "wrong-secret", sig)


class TestPBKDF2:
    def test_hash_and_verify(self):
        h, salt = sec.pbkdf2_hash("testpassword")
        assert sec.pbkdf2_verify("testpassword", h, salt)

    def test_wrong_password_fails(self):
        h, salt = sec.pbkdf2_hash("correctpassword")
        assert not sec.pbkdf2_verify("wrongpassword", h, salt)

    def test_unique_salts(self):
        _, s1 = sec.pbkdf2_hash("same")
        _, s2 = sec.pbkdf2_hash("same")
        assert s1 != s2  # salts should differ


class TestAESEncryption:
    def test_encrypt_decrypt_roundtrip(self):
        try:
            key, nonce, ct = sec.aes_encrypt(b"secret data")
            plain = sec.aes_decrypt(key, nonce, ct)
            assert plain == b"secret data"
        except RuntimeError:
            pytest.skip("cryptography not installed")

    def test_string_encrypt_decrypt(self):
        try:
            enc = sec.aes_encrypt_string("hello omnisec")
            plain = sec.aes_decrypt_string(enc)
            assert plain == "hello omnisec"
        except RuntimeError:
            pytest.skip("cryptography not installed")

    def test_different_ciphertexts(self):
        try:
            _, _, ct1 = sec.aes_encrypt(b"same")
            _, _, ct2 = sec.aes_encrypt(b"same")
            assert ct1 != ct2  # different nonces
        except RuntimeError:
            pytest.skip("cryptography not installed")


class TestPasswordTools:
    def test_generate_default(self):
        pwd = sec.generate_password()
        assert len(pwd) == 16

    def test_generate_custom_length(self):
        pwd = sec.generate_password(length=32)
        assert len(pwd) == 32

    def test_minimum_length_enforced(self):
        pwd = sec.generate_password(length=2)  # should be clamped to 8
        assert len(pwd) >= 8

    def test_strength_weak(self):
        r = sec.check_password_strength("abc")
        assert r["strength"] == "weak"

    def test_strength_strong(self):
        r = sec.check_password_strength("V3ryStr0ng!P@ssw0rd#2024")
        assert r["strength"] in ("good", "strong")

    def test_common_password_penalty(self):
        r = sec.check_password_strength("password")
        assert r["is_common"] is True
        assert r["score"] < 40

    def test_generate_otp_length(self):
        otp = sec.generate_otp(6)
        assert len(otp) == 6
        assert otp.isdigit()


class TestIoCExtraction:
    def test_extract_ipv4(self):
        iocs = sec.extract_iocs("Traffic from 192.168.1.50 and 10.0.0.1")
        assert "192.168.1.50" in iocs["ipv4"]
        assert "10.0.0.1" in iocs["ipv4"]

    def test_extract_cve(self):
        iocs = sec.extract_iocs("Exploiting CVE-2023-1234 and CVE-2024-56789")
        assert "CVE-2023-1234" in iocs["cves"]

    def test_extract_emails(self):
        iocs = sec.extract_iocs("Contact admin@example.com for details")
        assert "admin@example.com" in iocs["emails"]

    def test_extract_sha256(self):
        fake_hash = "a" * 64
        iocs = sec.extract_iocs(f"Malware hash: {fake_hash}")
        assert fake_hash in iocs["sha256"]


class TestIPValidation:
    def test_valid_ipv4(self):
        assert sec.is_valid_ip("192.168.1.1") is True

    def test_invalid_ip(self):
        assert sec.is_valid_ip("999.999.999.999") is False
        assert sec.is_valid_ip("not-an-ip") is False

    def test_private_ip(self):
        assert sec.is_private_ip("10.0.0.1") is True
        assert sec.is_private_ip("192.168.0.1") is True
        assert sec.is_private_ip("8.8.8.8") is False


class TestSecurityHeaders:
    def test_all_missing(self):
        result = sec.analyze_headers({})
        assert result["score"] == 0
        assert result["grade"] == "F"
        assert len(result["missing"]) > 0

    def test_partial_headers(self):
        headers = {
            "Strict-Transport-Security": "max-age=31536000",
            "X-Frame-Options": "DENY",
        }
        result = sec.analyze_headers(headers)
        assert result["score"] > 0
        assert "Strict-Transport-Security" in result["present"]

    def test_encoding_roundtrip(self):
        original = "hello world"
        encoded = sec.b64_encode(original)
        decoded = sec.b64_decode(encoded).decode()
        assert decoded == original


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
