#!perl
use 5.014;
use strict;
use warnings;
use Test::More tests => 8;

# Test Phase 2: Custom op infrastructure

BEGIN {
    use_ok('Medusa::XS') || BAIL_OUT("Cannot load Medusa::XS");
}

# ------------------------------------------------------------------ #
# Test _make_test_audit_op() - creates and frees an AUDITOP           #
# ------------------------------------------------------------------ #

subtest '_make_test_audit_op() creates AUDITOP' => sub {
    plan tests => 3;
    
    my $result = Medusa::XS::_make_test_audit_op("test_method", "Test::Package");
    ok(defined $result, 'Result is defined');
    like($result, qr/^AUDIT_CACHE\@Test::Package::test_method$/, 'Returns AUDIT_CACHE confirmation string');
    
    # Create another to ensure no memory issues
    my $result2 = Medusa::XS::_make_test_audit_op("another_method", "Another::Pkg");
    ok(defined $result2, 'Second AUDIT_CACHE created');
};

# ------------------------------------------------------------------ #
# Test wrap_sub() - wraps a CV with auditing                          #
# ------------------------------------------------------------------ #

subtest 'wrap_sub() marks CV as audited' => sub {
    plan tests => 4;
    
    sub test_sub_for_wrapping { return 42; }
    
    my $coderef = \&test_sub_for_wrapping;
    ok(ref($coderef) eq 'CODE', 'Got a coderef');
    
    # Before wrapping
    ok(!Medusa::XS::is_audited($coderef), 'CV is not audited initially');
    
    # Wrap it
    my $wrapped = Medusa::XS::wrap_sub($coderef);
    ok(defined $wrapped, 'wrap_sub() returns something');
    
    # After wrapping
    ok(Medusa::XS::is_audited($coderef), 'CV is marked as audited after wrap_sub()');
};

# ------------------------------------------------------------------ #
# Test is_audited() with various inputs                               #
# ------------------------------------------------------------------ #

subtest 'is_audited() handles various inputs' => sub {
    plan tests => 4;
    
    # Non-coderef returns false
    ok(!Medusa::XS::is_audited("string"), 'String returns false');
    ok(!Medusa::XS::is_audited(123), 'Number returns false');
    ok(!Medusa::XS::is_audited([1,2,3]), 'Arrayref returns false');
    
    # Fresh sub is not audited
    sub fresh_unwrapped_sub { return 1; }
    ok(!Medusa::XS::is_audited(\&fresh_unwrapped_sub), 'Fresh sub is not audited');
};

# ------------------------------------------------------------------ #
# Test that wrapping is idempotent                                    #
# ------------------------------------------------------------------ #

subtest 'wrap_sub() is idempotent' => sub {
    plan tests => 3;
    
    sub idempotent_test_sub { return 'hello'; }
    
    my $coderef = \&idempotent_test_sub;
    
    # First wrap
    Medusa::XS::wrap_sub($coderef);
    ok(Medusa::XS::is_audited($coderef), 'CV is audited after first wrap');
    
    # Second wrap - should not cause issues
    my $result = Medusa::XS::wrap_sub($coderef);
    ok(defined $result, 'Second wrap_sub() succeeds');
    ok(Medusa::XS::is_audited($coderef), 'CV is still audited');
};

# ------------------------------------------------------------------ #
# Test wrap_sub() with custom method name                             #
# ------------------------------------------------------------------ #

subtest 'wrap_sub() accepts custom method name' => sub {
    plan tests => 2;
    
    sub sub_with_custom_name { return 'test'; }
    
    my $coderef = \&sub_with_custom_name;
    my $wrapped = Medusa::XS::wrap_sub($coderef, "custom_audit_name");
    ok(defined $wrapped, 'wrap_sub() with custom name succeeds');
    ok(Medusa::XS::is_audited($coderef), 'CV is marked as audited');
};

# ------------------------------------------------------------------ #
# Test wrap_sub() with anonymous sub                                  #
# ------------------------------------------------------------------ #

subtest 'wrap_sub() works with anonymous subs' => sub {
    plan tests => 2;
    
    my $anon = sub { return "anonymous"; };
    
    my $wrapped = Medusa::XS::wrap_sub($anon);
    ok(defined $wrapped, 'wrap_sub() with anon sub succeeds');
    ok(Medusa::XS::is_audited($anon), 'Anon sub is marked as audited');
};

# ------------------------------------------------------------------ #
# Test wrap_sub() error handling                                      #
# ------------------------------------------------------------------ #

subtest 'wrap_sub() error handling' => sub {
    plan tests => 2;
    
    # Non-coderef should croak
    eval { Medusa::XS::wrap_sub("not a coderef"); };
    like($@, qr/argument must be a code reference/i, 'Croaks on non-coderef');
    
    eval { Medusa::XS::wrap_sub([1,2,3]); };
    like($@, qr/argument must be a code reference/i, 'Croaks on arrayref');
};
