<?php
/**
 * Unit tests for the Email Attendees Data class
 */

class Test_HVAC_Email_Attendees_Data extends WP_UnitTestCase {
    /**
     * @var int Test event ID
     */
    private $event_id;

    /**
     * @var int Test user ID
     */
    private $user_id;

    /**
     * Set up test data before each test
     */
    public function setUp(): void {
        parent::setUp();

        // Create a test user
        $this->user_id = $this->factory->user->create(array(
            'role' => 'hvac_trainer',
        ));

        // Set current user for permission testing
        wp_set_current_user($this->user_id);

        // Make sure the class exists
        require_once HVAC_CE_PLUGIN_DIR . 'includes/community/class-email-attendees-data.php';

        // Create a test event
        $event_data = array(
            'post_title'   => 'Test Event for Email Attendees',
            'post_content' => 'Test event content',
            'post_status'  => 'publish',
            'post_type'    => Tribe__Events__Main::POSTTYPE,
            'post_author'  => $this->user_id,
        );
        $this->event_id = wp_insert_post($event_data);

        // Mock tribe_tickets_get_attendees functionality if needed
        // This would require more setup depending on how deeply you want to test
    }

    /**
     * Clean up test data after each test
     */
    public function tearDown(): void {
        // Delete test event
        wp_delete_post($this->event_id, true);

        // Delete test user
        wp_delete_user($this->user_id);

        parent::tearDown();
    }

    /**
     * Test constructor
     */
    public function test_constructor() {
        $email_data = new HVAC_Email_Attendees_Data($this->event_id);
        $this->assertInstanceOf('HVAC_Email_Attendees_Data', $email_data);
    }

    /**
     * Test is_valid_event method
     */
    public function test_is_valid_event() {
        $email_data = new HVAC_Email_Attendees_Data($this->event_id);
        $this->assertTrue($email_data->is_valid_event());

        // Test with invalid event ID
        $email_data_invalid = new HVAC_Email_Attendees_Data(999999);
        $this->assertFalse($email_data_invalid->is_valid_event());

        // Test with empty event ID
        $email_data_empty = new HVAC_Email_Attendees_Data();
        $this->assertFalse($email_data_empty->is_valid_event());
    }

    /**
     * Test user_can_email_attendees method
     */
    public function test_user_can_email_attendees() {
        $email_data = new HVAC_Email_Attendees_Data($this->event_id);

        // Current user is event author, should return true
        $this->assertTrue($email_data->user_can_email_attendees());

        // Create another user who is not the event author
        $another_user_id = $this->factory->user->create(array(
            'role' => 'hvac_trainer',
        ));
        wp_set_current_user($another_user_id);

        // Another user without edit_posts capability should return false
        $this->assertFalse($email_data->user_can_email_attendees());

        // Create admin user
        $admin_user_id = $this->factory->user->create(array(
            'role' => 'administrator',
        ));
        wp_set_current_user($admin_user_id);

        // Admin with edit_posts capability should return true
        $this->assertTrue($email_data->user_can_email_attendees());

        // Reset to original user
        wp_set_current_user($this->user_id);
    }

    /**
     * Test get_event_details method
     */
    public function test_get_event_details() {
        $email_data = new HVAC_Email_Attendees_Data($this->event_id);
        $event_details = $email_data->get_event_details();

        // Verify event details contain expected data
        $this->assertIsArray($event_details);
        $this->assertEquals($this->event_id, $event_details['id']);
        $this->assertEquals('Test Event for Email Attendees', $event_details['title']);
    }

    /**
     * Test get_attendees and get_attendees_by_ticket_type methods with mocked data
     */
    public function test_get_attendees_with_mock_data() {
        // Create a test instance
        $email_data = $this->getMockBuilder('HVAC_Email_Attendees_Data')
            ->setConstructorArgs(array($this->event_id))
            ->setMethods(array('get_attendees'))
            ->getMock();

        // Mock attendee data
        $mock_attendees = array(
            array(
                'name' => 'Test Attendee 1',
                'email' => 'attendee1@example.com',
                'ticket_name' => 'General Admission',
                'attendee_id' => 101,
                'order_id' => 1001,
            ),
            array(
                'name' => 'Test Attendee 2',
                'email' => 'attendee2@example.com',
                'ticket_name' => 'VIP Pass',
                'attendee_id' => 102,
                'order_id' => 1002,
            ),
            array(
                'name' => 'Test Attendee 3',
                'email' => 'attendee3@example.com',
                'ticket_name' => 'General Admission',
                'attendee_id' => 103,
                'order_id' => 1003,
            ),
        );

        // Configure mock to return test data
        $email_data->expects($this->any())
            ->method('get_attendees')
            ->will($this->returnValue($mock_attendees));

        // Use reflection to access non-public methods for testing
        $reflection = new ReflectionClass('HVAC_Email_Attendees_Data');
        $method = $reflection->getMethod('get_attendees_by_ticket_type');
        $method->setAccessible(true);

        // Test filtering by ticket type
        $general_admission = $method->invokeArgs($email_data, array('General Admission'));
        $this->assertCount(2, $general_admission);
        $this->assertEquals('Test Attendee 1', $general_admission[0]['name']);
        $this->assertEquals('Test Attendee 3', $general_admission[2]['name']);

        // Test filtering by another ticket type
        $vip_pass = $method->invokeArgs($email_data, array('VIP Pass'));
        $this->assertCount(1, $vip_pass);
        $this->assertEquals('Test Attendee 2', $vip_pass[0]['name']);

        // Test getting all attendees (no filter)
        $all_attendees = $method->invokeArgs($email_data, array(''));
        $this->assertCount(3, $all_attendees);
    }

    /**
     * Test get_ticket_types method with mocked data
     */
    public function test_get_ticket_types_with_mock_data() {
        // Create a test instance
        $email_data = $this->getMockBuilder('HVAC_Email_Attendees_Data')
            ->setConstructorArgs(array($this->event_id))
            ->setMethods(array('get_attendees'))
            ->getMock();

        // Mock attendee data
        $mock_attendees = array(
            array(
                'name' => 'Test Attendee 1',
                'email' => 'attendee1@example.com',
                'ticket_name' => 'General Admission',
                'attendee_id' => 101,
                'order_id' => 1001,
            ),
            array(
                'name' => 'Test Attendee 2',
                'email' => 'attendee2@example.com',
                'ticket_name' => 'VIP Pass',
                'attendee_id' => 102,
                'order_id' => 1002,
            ),
            array(
                'name' => 'Test Attendee 3',
                'email' => 'attendee3@example.com',
                'ticket_name' => 'General Admission',
                'attendee_id' => 103,
                'order_id' => 1003,
            ),
        );

        // Configure mock to return test data
        $email_data->expects($this->any())
            ->method('get_attendees')
            ->will($this->returnValue($mock_attendees));

        // Use reflection to access the get_ticket_types method
        $reflection = new ReflectionClass('HVAC_Email_Attendees_Data');
        $method = $reflection->getMethod('get_ticket_types');
        $method->setAccessible(true);

        // Test getting ticket types
        $ticket_types = $method->invoke($email_data);
        $this->assertIsArray($ticket_types);
        $this->assertCount(2, $ticket_types);
        $this->assertContains('General Admission', $ticket_types);
        $this->assertContains('VIP Pass', $ticket_types);
    }

    /**
     * Test send_email method with mocked wp_mail
     */
    public function test_send_email() {
        global $wp_mail_called, $wp_mail_args;
        
        // Override wp_mail for testing
        $wp_mail_called = 0;
        $wp_mail_args = array();
        
        function test_wp_mail($to, $subject, $message, $headers = '', $attachments = array()) {
            global $wp_mail_called, $wp_mail_args;
            $wp_mail_called++;
            $wp_mail_args[] = array(
                'to' => $to,
                'subject' => $subject,
                'message' => $message,
                'headers' => $headers,
                'attachments' => $attachments,
            );
            return true;
        }
        
        // Replace WordPress's wp_mail with our test version
        add_filter('wp_mail', 'test_wp_mail', 10, 5);
        
        // Create a test instance
        $email_data = $this->getMockBuilder('HVAC_Email_Attendees_Data')
            ->setConstructorArgs(array($this->event_id))
            ->setMethods(array('is_valid_event', 'user_can_email_attendees', 'get_attendees', 'get_event_details'))
            ->getMock();
        
        // Mock necessary methods
        $email_data->expects($this->any())
            ->method('is_valid_event')
            ->will($this->returnValue(true));
            
        $email_data->expects($this->any())
            ->method('user_can_email_attendees')
            ->will($this->returnValue(true));
            
        $email_data->expects($this->any())
            ->method('get_event_details')
            ->will($this->returnValue(array(
                'id' => $this->event_id,
                'title' => 'Test Event for Email Attendees',
                'start_date' => date('F j, Y'),
                'start_time' => '10:00 am',
                'end_date' => date('F j, Y'),
                'end_time' => '4:00 pm',
            )));
            
        $mock_attendees = array(
            array(
                'name' => 'Test Attendee 1',
                'email' => 'attendee1@example.com',
                'ticket_name' => 'General Admission',
                'attendee_id' => 101,
                'order_id' => 1001,
            ),
            array(
                'name' => 'Test Attendee 2',
                'email' => 'attendee2@example.com',
                'ticket_name' => 'VIP Pass',
                'attendee_id' => 102,
                'order_id' => 1002,
            ),
        );
        
        $email_data->expects($this->any())
            ->method('get_attendees')
            ->will($this->returnValue($mock_attendees));
        
        // Test sending email
        $recipients = array('attendee1@example.com', 'attendee2@example.com');
        $subject = 'Test Email Subject';
        $message = 'Test email message body';
        $cc = 'cc@example.com';
        
        $result = $email_data->send_email($recipients, $subject, $message, $cc);
        
        // Verify email was sent successfully
        $this->assertTrue($result['success']);
        $this->assertEquals(2, $wp_mail_called); // One email per recipient
        
        // Verify email content
        $this->assertEquals('attendee1@example.com', $wp_mail_args[0]['to']);
        $this->assertStringContains('[Test Event for Email Attendees]', $wp_mail_args[0]['subject']);
        $this->assertStringContains('Test email message body', $wp_mail_args[0]['message']);
        
        // Verify CC header
        foreach ($wp_mail_args as $args) {
            $this->assertStringContains('Cc: cc@example.com', implode("\n", $args['headers']));
        }
        
        // Test with invalid parameters
        $result = $email_data->send_email(array(), $subject, $message);
        $this->assertFalse($result['success']);
        
        // Clean up
        remove_filter('wp_mail', 'test_wp_mail');
    }
}