<?php
/**
 * Extended Unit Tests for HVAC Announcements Email Handler
 *
 * @package HVAC_Community_Events
 * @subpackage Tests
 */

class Test_HVAC_Announcements_Email_Extended extends WP_UnitTestCase {
    
    /**
     * Email handler instance
     */
    private $email_handler;
    
    /**
     * Test users
     */
    private $test_users = array();
    
    /**
     * Setup before each test
     */
    public function setUp() {
        parent::setUp();
        
        // Create multiple test users with different statuses
        $this->test_users['active'] = $this->factory->user->create( array(
            'role' => 'hvac_trainer',
            'user_login' => 'active_trainer',
            'user_email' => 'active@example.com',
        ) );
        
        $this->test_users['pending'] = $this->factory->user->create( array(
            'role' => 'hvac_trainer',
            'user_login' => 'pending_trainer',
            'user_email' => 'pending@example.com',
        ) );
        update_user_meta( $this->test_users['pending'], 'account_status', 'pending' );
        
        $this->test_users['disabled'] = $this->factory->user->create( array(
            'role' => 'hvac_trainer',
            'user_login' => 'disabled_trainer',
            'user_email' => 'disabled@example.com',
        ) );
        update_user_meta( $this->test_users['disabled'], 'account_status', 'disabled' );
        
        $this->test_users['opted_out'] = $this->factory->user->create( array(
            'role' => 'hvac_trainer',
            'user_login' => 'opted_out_trainer',
            'user_email' => 'optedout@example.com',
        ) );
        update_user_meta( $this->test_users['opted_out'], 'hvac_announcement_emails_opt_out', 'yes' );
        
        $this->test_users['no_email'] = $this->factory->user->create( array(
            'role' => 'hvac_trainer',
            'user_login' => 'no_email_trainer',
            'user_email' => '',
        ) );
        
        $this->test_users['invalid_email'] = $this->factory->user->create( array(
            'role' => 'hvac_trainer',
            'user_login' => 'invalid_email_trainer',
            'user_email' => 'not_an_email',
        ) );
        
        // Add capabilities
        HVAC_Announcements_Permissions::add_capabilities();
        
        // Get email handler instance
        $this->email_handler = HVAC_Announcements_Email::get_instance();
    }
    
    /**
     * Teardown after each test
     */
    public function tearDown() {
        parent::tearDown();
        
        // Clean up test users
        foreach ( $this->test_users as $user_id ) {
            wp_delete_user( $user_id );
        }
        
        // Remove capabilities
        HVAC_Announcements_Permissions::remove_capabilities();
    }
    
    /**
     * Test email queue with mixed user statuses
     */
    public function test_queue_emails_mixed_statuses() {
        // Create test announcement
        $post_id = wp_insert_post( array(
            'post_type' => HVAC_Announcements_CPT::get_post_type(),
            'post_title' => 'Test Announcement',
            'post_content' => 'Content',
            'post_status' => 'draft',
        ) );
        
        // Queue emails
        $reflection = new ReflectionClass( $this->email_handler );
        $method = $reflection->getMethod( 'queue_announcement_emails' );
        $method->setAccessible( true );
        $method->invoke( $this->email_handler, $post_id );
        
        // Get recipients
        $recipients = get_post_meta( $post_id, '_hvac_announcement_email_recipients', true );
        
        // Should only include active trainer
        $this->assertContains( $this->test_users['active'], $recipients );
        $this->assertNotContains( $this->test_users['pending'], $recipients );
        $this->assertNotContains( $this->test_users['disabled'], $recipients );
        $this->assertNotContains( $this->test_users['opted_out'], $recipients );
        $this->assertNotContains( $this->test_users['no_email'], $recipients );
        $this->assertNotContains( $this->test_users['invalid_email'], $recipients );
        
        // Clean up
        wp_delete_post( $post_id, true );
    }
    
    /**
     * Test email batch processing
     */
    public function test_email_batch_processing() {
        // Create many users to test batching
        $many_users = array();
        for ( $i = 1; $i <= 150; $i++ ) {
            $many_users[] = $this->factory->user->create( array(
                'role' => 'hvac_trainer',
                'user_login' => 'trainer_' . $i,
                'user_email' => 'trainer' . $i . '@example.com',
            ) );
        }
        
        // Create announcement
        $post_id = wp_insert_post( array(
            'post_type' => HVAC_Announcements_CPT::get_post_type(),
            'post_title' => 'Batch Test',
            'post_status' => 'publish',
        ) );
        
        // Test batch size
        $reflection = new ReflectionClass( $this->email_handler );
        $batch_size_prop = $reflection->getProperty( 'batch_size' );
        $batch_size_prop->setAccessible( true );
        $batch_size = $batch_size_prop->getValue( $this->email_handler );
        
        // Calculate expected batches
        $total_users = count( $many_users ) + 1; // +1 for active trainer
        $expected_batches = ceil( $total_users / $batch_size );
        
        // Test chunking
        $chunks = array_chunk( $many_users, $batch_size );
        $this->assertEquals( $expected_batches, count( $chunks ) );
        
        // Clean up
        foreach ( $many_users as $user_id ) {
            wp_delete_user( $user_id );
        }
        wp_delete_post( $post_id, true );
    }
    
    /**
     * Test status transition handling
     */
    public function test_status_transition_handling() {
        // Create announcement
        $post_id = wp_insert_post( array(
            'post_type' => HVAC_Announcements_CPT::get_post_type(),
            'post_title' => 'Transition Test',
            'post_status' => 'draft',
        ) );
        
        // Test draft to publish (should trigger email)
        $this->email_handler->handle_status_transition( 'publish', 'draft', get_post( $post_id ) );
        
        // Check if email was queued
        $send_date = get_post_meta( $post_id, '_hvac_announcement_email_send_date', true );
        $this->assertNotEmpty( $send_date );
        
        // Mark as sent
        update_post_meta( $post_id, '_hvac_announcement_email_sent', true );
        
        // Test publish to draft and back (should not re-send)
        $this->email_handler->handle_status_transition( 'draft', 'publish', get_post( $post_id ) );
        $this->email_handler->handle_status_transition( 'publish', 'draft', get_post( $post_id ) );
        
        // Email sent flag should still be true
        $email_sent = get_post_meta( $post_id, '_hvac_announcement_email_sent', true );
        $this->assertTrue( $email_sent );
        
        // Clean up
        wp_delete_post( $post_id, true );
    }
    
    /**
     * Test email with featured image
     */
    public function test_email_with_featured_image() {
        // Create announcement with featured image
        $post_id = wp_insert_post( array(
            'post_type' => HVAC_Announcements_CPT::get_post_type(),
            'post_title' => 'Image Test',
            'post_content' => 'Content with image',
            'post_status' => 'publish',
        ) );
        
        // Add featured image
        $attachment_id = $this->factory->attachment->create_upload_object( 
            DIR_TESTDATA . '/images/test-image.jpg', 
            $post_id 
        );
        set_post_thumbnail( $post_id, $attachment_id );
        
        // Get email body
        $reflection = new ReflectionClass( $this->email_handler );
        $method = $reflection->getMethod( 'get_email_body' );
        $method->setAccessible( true );
        $body = $method->invoke( $this->email_handler, get_post( $post_id ) );
        
        // Should contain image
        $this->assertStringContainsString( '<img', $body );
        $this->assertStringContainsString( 'wp-post-image', $body );
        
        // Clean up
        wp_delete_post( $post_id, true );
        wp_delete_attachment( $attachment_id, true );
    }
    
    /**
     * Test email with categories and tags
     */
    public function test_email_with_taxonomies() {
        // Create announcement
        $post_id = wp_insert_post( array(
            'post_type' => HVAC_Announcements_CPT::get_post_type(),
            'post_title' => 'Taxonomy Test',
            'post_status' => 'publish',
        ) );
        
        // Add categories and tags
        $cat_ids = array();
        $cat_ids[] = wp_insert_term( 'Email Cat 1', HVAC_Announcements_CPT::get_category_taxonomy() );
        $cat_ids[] = wp_insert_term( 'Email Cat 2', HVAC_Announcements_CPT::get_category_taxonomy() );
        
        wp_set_post_terms( 
            $post_id, 
            array( $cat_ids[0]['term_id'], $cat_ids[1]['term_id'] ), 
            HVAC_Announcements_CPT::get_category_taxonomy() 
        );
        
        wp_set_post_terms( 
            $post_id, 
            array( 'email-tag-1', 'email-tag-2' ), 
            HVAC_Announcements_CPT::get_tag_taxonomy() 
        );
        
        // Get email body
        $reflection = new ReflectionClass( $this->email_handler );
        $method = $reflection->getMethod( 'get_fallback_email_body' );
        $method->setAccessible( true );
        $body = $method->invoke( $this->email_handler, get_post( $post_id ) );
        
        // Should contain title and basic structure
        $this->assertStringContainsString( 'Taxonomy Test', $body );
        $this->assertStringContainsString( 'Upskill HVAC', $body );
        
        // Clean up
        wp_delete_post( $post_id, true );
        foreach ( $cat_ids as $cat ) {
            if ( !is_wp_error( $cat ) ) {
                wp_delete_term( $cat['term_id'], HVAC_Announcements_CPT::get_category_taxonomy() );
            }
        }
    }
    
    /**
     * Test email headers with different admin email scenarios
     */
    public function test_email_headers_fallback() {
        $reflection = new ReflectionClass( $this->email_handler );
        $method = $reflection->getMethod( 'get_email_headers' );
        $method->setAccessible( true );
        
        // Test with valid admin email
        $original_email = get_option( 'admin_email' );
        update_option( 'admin_email', 'valid@example.com' );
        
        $headers = $method->invoke( $this->email_handler );
        $this->assertStringContainsString( 'valid@example.com', implode( "\n", $headers ) );
        
        // Test with empty admin email
        update_option( 'admin_email', '' );
        $headers = $method->invoke( $this->email_handler );
        
        // Should use fallback
        $this->assertNotEmpty( $headers );
        $from_header = $headers[1];
        $this->assertStringContainsString( 'From:', $from_header );
        
        // Test with invalid admin email
        update_option( 'admin_email', 'not-valid-email' );
        $headers = $method->invoke( $this->email_handler );
        
        // Should use fallback
        $this->assertNotEmpty( $headers );
        
        // Restore original
        update_option( 'admin_email', $original_email );
    }
    
    /**
     * Test retry mechanism exhaustion
     */
    public function test_retry_exhaustion() {
        $post_id = wp_insert_post( array(
            'post_type' => HVAC_Announcements_CPT::get_post_type(),
            'post_title' => 'Retry Test',
            'post_status' => 'publish',
        ) );
        
        $reflection = new ReflectionClass( $this->email_handler );
        $method = $reflection->getMethod( 'maybe_schedule_retry' );
        $method->setAccessible( true );
        
        $user_id = $this->test_users['active'];
        
        // Exhaust retries
        for ( $i = 1; $i <= 5; $i++ ) {
            $method->invoke( $this->email_handler, $post_id, $user_id );
        }
        
        // Check retry count is capped at 3
        $retry_count = get_user_meta( $user_id, '_hvac_announcement_email_retry_' . $post_id, true );
        $this->assertEquals( 3, $retry_count );
        
        // Clean up
        wp_delete_post( $post_id, true );
        delete_user_meta( $user_id, '_hvac_announcement_email_retry_' . $post_id );
    }
    
    /**
     * Test email logging with different statuses
     */
    public function test_email_logging_statuses() {
        $post_id = wp_insert_post( array(
            'post_type' => HVAC_Announcements_CPT::get_post_type(),
            'post_title' => 'Log Test',
            'post_status' => 'publish',
        ) );
        
        $reflection = new ReflectionClass( $this->email_handler );
        $method = $reflection->getMethod( 'log_email_send' );
        $method->setAccessible( true );
        
        // Log different statuses
        $method->invoke( $this->email_handler, $post_id, 1, 'success' );
        $method->invoke( $this->email_handler, $post_id, 2, 'failed' );
        $method->invoke( $this->email_handler, $post_id, 3, 'invalid_email' );
        $method->invoke( $this->email_handler, $post_id, 4, 'success' );
        
        // Get log
        $log = get_post_meta( $post_id, '_hvac_announcement_email_log', true );
        
        $this->assertCount( 4, $log );
        $this->assertEquals( 'success', $log[0]['status'] );
        $this->assertEquals( 'failed', $log[1]['status'] );
        $this->assertEquals( 'invalid_email', $log[2]['status'] );
        $this->assertEquals( 'success', $log[3]['status'] );
        
        // Test email status calculation
        $status = HVAC_Announcements_Email::get_email_status( $post_id );
        $this->assertEquals( 2, $status['successful'] );
        $this->assertEquals( 2, $status['failed'] ); // failed + invalid_email
        
        // Clean up
        wp_delete_post( $post_id, true );
    }
    
    /**
     * Test email subject and body filters
     */
    public function test_email_filters() {
        $post_id = wp_insert_post( array(
            'post_type' => HVAC_Announcements_CPT::get_post_type(),
            'post_title' => 'Filter Test',
            'post_content' => 'Original content',
            'post_status' => 'publish',
        ) );
        
        $post = get_post( $post_id );
        
        // Add filter to modify subject
        add_filter( 'hvac_announcement_email_subject', function( $subject, $post ) {
            return 'Modified: ' . $subject;
        }, 10, 2 );
        
        // Add filter to modify body
        add_filter( 'hvac_announcement_email_body', function( $body, $post ) {
            return $body . '<!-- Modified -->';
        }, 10, 2 );
        
        // Add filter to modify headers
        add_filter( 'hvac_announcement_email_headers', function( $headers ) {
            $headers[] = 'X-Custom-Header: Test';
            return $headers;
        } );
        
        $reflection = new ReflectionClass( $this->email_handler );
        
        // Test subject filter
        $subject_method = $reflection->getMethod( 'get_email_subject' );
        $subject_method->setAccessible( true );
        $subject = $subject_method->invoke( $this->email_handler, $post );
        $this->assertStringStartsWith( 'Modified:', $subject );
        
        // Test body filter
        $body_method = $reflection->getMethod( 'get_email_body' );
        $body_method->setAccessible( true );
        $body = $body_method->invoke( $this->email_handler, $post );
        $this->assertStringContainsString( '<!-- Modified -->', $body );
        
        // Test headers filter
        $headers_method = $reflection->getMethod( 'get_email_headers' );
        $headers_method->setAccessible( true );
        $headers = $headers_method->invoke( $this->email_handler );
        $this->assertContains( 'X-Custom-Header: Test', $headers );
        
        // Remove filters
        remove_all_filters( 'hvac_announcement_email_subject' );
        remove_all_filters( 'hvac_announcement_email_body' );
        remove_all_filters( 'hvac_announcement_email_headers' );
        
        // Clean up
        wp_delete_post( $post_id, true );
    }
}