<?php

/**
 * Tests for the HVAC_Role_Manager class
 * 
 * @package HVAC\Testing
 */
class HVAC_Role_Manager_Test extends HVAC_Base_Test_Case {
    /** @var HVAC_Role_Manager */
    private $role_manager;

    /**
     * Set up test environment
     */
    public function setUp(): void {
        parent::setUp();
        $this->role_manager = new HVAC_Role_Manager();
    }

    /**
     * Clean up after each test
     */
    public function tearDown(): void {
        $this->role_manager->cleanup_transaction_roles();
        parent::tearDown();
    }

    /**
     * @testdox Basic role operations create and verify roles correctly
     */
    public function test_basic_role_operations(): void {
        // Create a basic role
        $result = $this->role_manager->create_role(
            'test_editor',
            'Test Editor',
            ['edit_posts' => true]
        );
        
        $this->assertTrue($result);
        $this->assertTrue($this->role_manager->role_exists('test_editor'));
        
        // Verify capabilities
        $caps = $this->role_manager->get_role_capabilities('test_editor');
        $this->assertArrayHasKey('edit_posts', $caps);
    }

    /**
     * @testdox Role creation validates input parameters
     * @dataProvider provide_invalid_role_data
     */
    public function test_role_creation_validation(
        string $role_name,
        string $display_name,
        array $capabilities,
        string $expected_exception
    ): void {
        $this->expectException(InvalidArgumentException::class);
        $this->expectExceptionMessage($expected_exception);
        
        $this->role_manager->create_role($role_name, $display_name, $capabilities);
    }

    /**
     * Data provider for role creation validation tests
     */
    public function provide_invalid_role_data(): array {
        return [
            'empty_role_name' => [
                '',
                'Display Name',
                ['edit_posts' => true],
                'Role name and display name are required'
            ],
            'empty_display_name' => [
                'role_name',
                '',
                ['edit_posts' => true],
                'Role name and display name are required'
            ],
            'duplicate_role' => [
                'administrator',
                'Admin',
                ['edit_posts' => true],
                "Role 'administrator' already exists"
            ]
        ];
    }

    /**
     * @testdox Permission inheritance works correctly
     */
    public function test_role_inheritance(): void {
        // Create parent role
        $this->role_manager->create_role(
            'parent_role',
            'Parent Role',
            ['parent_cap' => true]
        );

        // Create child role inheriting from parent
        $result = $this->role_manager->create_role(
            'child_role',
            'Child Role',
            ['child_cap' => true],
            ['parent_role']
        );

        $this->assertTrue($result);
        
        // Verify inherited capabilities
        $caps = $this->role_manager->get_role_capabilities('child_role');
        $this->assertArrayHasKey('parent_cap', $caps);
        $this->assertArrayHasKey('child_cap', $caps);
    }

    /**
     * @testdox Core WordPress roles cannot be deleted
     */
    public function test_core_role_deletion_prevention(): void {
        $core_roles = ['administrator', 'editor', 'author', 'contributor', 'subscriber'];
        
        foreach ($core_roles as $role) {
            try {
                $this->role_manager->delete_role($role);
                $this->fail("Expected exception when deleting core role: {$role}");
            } catch (InvalidArgumentException $e) {
                $this->assertStringContainsString("Cannot delete core WordPress role", $e->getMessage());
            }
        }
    }

    /**
     * @testdox Capability management functions work correctly
     */
    public function test_capability_management(): void {
        // Create test role
        $this->role_manager->create_role(
            'cap_test_role',
            'Capability Test Role',
            ['initial_cap' => true]
        );

        // Add capabilities
        $new_caps = ['new_cap_1', 'new_cap_2'];
        $result = $this->role_manager->add_capabilities('cap_test_role', $new_caps);
        $this->assertTrue($result);

        // Verify added capabilities
        $caps = $this->role_manager->get_role_capabilities('cap_test_role');
        foreach ($new_caps as $cap) {
            $this->assertArrayHasKey($cap, $caps);
        }

        // Remove capabilities
        $result = $this->role_manager->remove_capabilities('cap_test_role', ['new_cap_1']);
        $this->assertTrue($result);

        // Verify removal
        $caps = $this->role_manager->get_role_capabilities('cap_test_role');
        $this->assertArrayNotHasKey('new_cap_1', $caps);
        $this->assertArrayHasKey('new_cap_2', $caps);
    }

    /**
     * @testdox Role conflict detection works correctly
     */
    public function test_role_conflict_detection(): void {
        // Create roles with conflicting capabilities
        $this->role_manager->create_role(
            'role_1',
            'Role 1',
            ['publish_posts' => true]
        );

        $this->role_manager->create_role(
            'role_2',
            'Role 2',
            ['read_only_posts' => true]
        );

        // Check for conflicts
        $conflicts = $this->role_manager->detect_role_conflicts(['role_1', 'role_2']);
        
        $this->assertNotEmpty($conflicts);
        $this->assertCount(1, $conflicts);
        $this->assertEquals(['publish_posts', 'read_only_posts'], $conflicts[0]['conflicts'][0]);
    }

    /**
     * @testdox TEC capabilities are properly assigned to core roles
     */
    public function test_tec_capability_assignment(): void {
        // Check administrator capabilities
        $admin_caps = $this->role_manager->get_role_capabilities('administrator');
        $this->assertArrayHasKey('publish_tribe_events', $admin_caps);
        $this->assertArrayHasKey('manage_tribe_event_settings', $admin_caps);

        // Check editor capabilities
        $editor_caps = $this->role_manager->get_role_capabilities('editor');
        $this->assertArrayHasKey('publish_tribe_events', $editor_caps);
        $this->assertArrayNotHasKey('manage_tribe_event_settings', $editor_caps);
    }

    /**
     * @testdox Transaction roles are properly cleaned up
     */
    public function test_transaction_role_cleanup(): void {
        // Create multiple test roles
        $test_roles = ['test_role_1', 'test_role_2', 'test_role_3'];
        
        foreach ($test_roles as $role) {
            $this->role_manager->create_role($role, "Test Role", ['test_cap' => true]);
            $this->assertTrue($this->role_manager->role_exists($role));
        }

        // Clean up transaction roles
        $this->role_manager->cleanup_transaction_roles();

        // Verify roles are removed
        foreach ($test_roles as $role) {
            $this->assertFalse($this->role_manager->role_exists($role));
        }
    }
}