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

class Test_HVAC_Announcements_Email extends WP_UnitTestCase {
    
    /**
     * Test announcement
     */
    private $test_announcement;
    
    /**
     * Test users
     */
    private $test_trainers = array();
    
    /**
     * Setup before each test
     */
    public function setUp() {
        parent::setUp();
        
        // Create test trainers
        for ( $i = 1; $i <= 3; $i++ ) {
            $this->test_trainers[] = $this->factory->user->create( array(
                'role' => 'hvac_trainer',
                'user_login' => 'trainer_' . $i,
                'user_email' => 'trainer' . $i . '@example.com',
                'display_name' => 'Trainer ' . $i,
            ) );
        }
        
        // Add capabilities
        HVAC_Announcements_Permissions::add_capabilities();
        
        // Create test announcement
        $this->test_announcement = wp_insert_post( array(
            'post_type' => HVAC_Announcements_CPT::get_post_type(),
            'post_title' => 'Test Announcement for Email',
            'post_content' => 'This is the content of the test announcement.',
            'post_excerpt' => 'Test excerpt',
            'post_status' => 'draft',
            'post_author' => $this->test_trainers[0],
        ) );
    }
    
    /**
     * Teardown after each test
     */
    public function tearDown() {
        parent::tearDown();
        
        // Clean up test announcement
        if ( $this->test_announcement ) {
            wp_delete_post( $this->test_announcement, true );
        }
        
        // Clean up test users
        foreach ( $this->test_trainers as $user_id ) {
            wp_delete_user( $user_id );
        }
        
        // Remove capabilities
        HVAC_Announcements_Permissions::remove_capabilities();
    }
    
    /**
     * Test email status tracking
     */
    public function test_email_status_tracking() {
        // Initially no email sent
        $status = HVAC_Announcements_Email::get_email_status( $this->test_announcement );
        $this->assertFalse( $status['sent'] );
        $this->assertEquals( 0, $status['total_recipients'] );
        $this->assertEquals( 0, $status['successful'] );
        $this->assertEquals( 0, $status['failed'] );
        
        // Mark as sent
        update_post_meta( $this->test_announcement, '_hvac_announcement_email_sent', true );
        update_post_meta( $this->test_announcement, '_hvac_announcement_email_recipients', $this->test_trainers );
        
        $status = HVAC_Announcements_Email::get_email_status( $this->test_announcement );
        $this->assertTrue( $status['sent'] );
        $this->assertEquals( 3, $status['total_recipients'] );
    }
    
    /**
     * Test email validation in headers
     */
    public function test_email_header_validation() {
        // Mock invalid admin email
        update_option( 'admin_email', 'invalid-email' );
        
        $email_handler = HVAC_Announcements_Email::get_instance();
        $reflection = new ReflectionClass( $email_handler );
        $method = $reflection->getMethod( 'get_email_headers' );
        $method->setAccessible( true );
        
        $headers = $method->invoke( $email_handler );
        
        // Should have Content-Type header
        $this->assertContains( 'Content-Type: text/html; charset=UTF-8', $headers );
        
        // Should have From header with fallback email
        $from_header = $headers[1];
        $this->assertStringContainsString( 'From:', $from_header );
        
        // Restore original admin email
        update_option( 'admin_email', 'admin@example.com' );
    }
    
    /**
     * Test batch size filter
     */
    public function test_batch_size_filter() {
        // Test default batch size
        $email_handler = HVAC_Announcements_Email::get_instance();
        $reflection = new ReflectionClass( $email_handler );
        $batch_size_prop = $reflection->getProperty( 'batch_size' );
        $batch_size_prop->setAccessible( true );
        
        $default_batch_size = $batch_size_prop->getValue( $email_handler );
        $this->assertEquals( 50, $default_batch_size );
        
        // Test filter
        add_filter( 'hvac_announcement_email_batch_size', function() {
            return 25;
        } );
        
        // Create new instance to apply filter
        $reflection_constructor = $reflection->getConstructor();
        $new_instance = $reflection->newInstanceWithoutConstructor();
        $reflection_constructor->invoke( $new_instance );
        
        $filtered_batch_size = $batch_size_prop->getValue( $new_instance );
        $this->assertEquals( 25, $filtered_batch_size );
        
        // Remove filter
        remove_all_filters( 'hvac_announcement_email_batch_size' );
    }
    
    /**
     * Test email subject generation
     */
    public function test_email_subject() {
        $post = get_post( $this->test_announcement );
        
        $email_handler = HVAC_Announcements_Email::get_instance();
        $reflection = new ReflectionClass( $email_handler );
        $method = $reflection->getMethod( 'get_email_subject' );
        $method->setAccessible( true );
        
        $subject = $method->invoke( $email_handler, $post );
        
        $this->assertStringContainsString( 'Upskill HVAC Trainer Announcement:', $subject );
        $this->assertStringContainsString( 'Test Announcement for Email', $subject );
    }
    
    /**
     * Test email body generation
     */
    public function test_email_body() {
        $post = get_post( $this->test_announcement );
        
        $email_handler = HVAC_Announcements_Email::get_instance();
        $reflection = new ReflectionClass( $email_handler );
        $method = $reflection->getMethod( 'get_email_body' );
        $method->setAccessible( true );
        
        $body = $method->invoke( $email_handler, $post );
        
        // Should contain HTML structure
        $this->assertStringContainsString( '<!DOCTYPE html>', $body );
        $this->assertStringContainsString( '<html>', $body );
        $this->assertStringContainsString( '</html>', $body );
        
        // Should contain announcement title
        $this->assertStringContainsString( 'Test Announcement for Email', $body );
        
        // Should contain announcement content
        $this->assertStringContainsString( 'This is the content of the test announcement.', $body );
    }
    
    /**
     * Test fallback email body
     */
    public function test_fallback_email_body() {
        $post = get_post( $this->test_announcement );
        
        $email_handler = HVAC_Announcements_Email::get_instance();
        $reflection = new ReflectionClass( $email_handler );
        $method = $reflection->getMethod( 'get_fallback_email_body' );
        $method->setAccessible( true );
        
        $body = $method->invoke( $email_handler, $post );
        
        // Should contain HTML structure
        $this->assertStringContainsString( '<!DOCTYPE html>', $body );
        $this->assertStringContainsString( 'Upskill HVAC Trainer Announcement', $body );
        $this->assertStringContainsString( 'Test Announcement for Email', $body );
        $this->assertStringContainsString( 'You received this email because you are registered as an HVAC Trainer', $body );
    }
    
    /**
     * Test email logging
     */
    public function test_email_logging() {
        $email_handler = HVAC_Announcements_Email::get_instance();
        $reflection = new ReflectionClass( $email_handler );
        $method = $reflection->getMethod( 'log_email_send' );
        $method->setAccessible( true );
        
        // Log successful send
        $method->invoke( $email_handler, $this->test_announcement, $this->test_trainers[0], 'success' );
        
        // Log failed send
        $method->invoke( $email_handler, $this->test_announcement, $this->test_trainers[1], 'failed' );
        
        // Check log
        $log = get_post_meta( $this->test_announcement, '_hvac_announcement_email_log', true );
        $this->assertIsArray( $log );
        $this->assertCount( 2, $log );
        
        $this->assertEquals( $this->test_trainers[0], $log[0]['user_id'] );
        $this->assertEquals( 'success', $log[0]['status'] );
        
        $this->assertEquals( $this->test_trainers[1], $log[1]['user_id'] );
        $this->assertEquals( 'failed', $log[1]['status'] );
    }
    
    /**
     * Test retry mechanism
     */
    public function test_retry_mechanism() {
        $email_handler = HVAC_Announcements_Email::get_instance();
        $reflection = new ReflectionClass( $email_handler );
        $method = $reflection->getMethod( 'maybe_schedule_retry' );
        $method->setAccessible( true );
        
        // First retry
        $method->invoke( $email_handler, $this->test_announcement, $this->test_trainers[0] );
        $retry_count = get_user_meta( $this->test_trainers[0], '_hvac_announcement_email_retry_' . $this->test_announcement, true );
        $this->assertEquals( 1, $retry_count );
        
        // Second retry
        $method->invoke( $email_handler, $this->test_announcement, $this->test_trainers[0] );
        $retry_count = get_user_meta( $this->test_trainers[0], '_hvac_announcement_email_retry_' . $this->test_announcement, true );
        $this->assertEquals( 2, $retry_count );
        
        // Third retry
        $method->invoke( $email_handler, $this->test_announcement, $this->test_trainers[0] );
        $retry_count = get_user_meta( $this->test_trainers[0], '_hvac_announcement_email_retry_' . $this->test_announcement, true );
        $this->assertEquals( 3, $retry_count );
        
        // Fourth retry should not increase (max 3)
        $method->invoke( $email_handler, $this->test_announcement, $this->test_trainers[0] );
        $retry_count = get_user_meta( $this->test_trainers[0], '_hvac_announcement_email_retry_' . $this->test_announcement, true );
        $this->assertEquals( 3, $retry_count );
    }
    
    /**
     * Test singleton pattern
     */
    public function test_singleton_pattern() {
        $instance1 = HVAC_Announcements_Email::get_instance();
        $instance2 = HVAC_Announcements_Email::get_instance();
        
        $this->assertSame( $instance1, $instance2 );
    }
}