<?php
/**
 * Tests for MLF_Ajax_Handler class.
 *
 * @package Maple_Local_Fonts
 */

/**
 * Class Test_MLF_Ajax_Handler
 *
 * @covers MLF_Ajax_Handler
 */
class Test_MLF_Ajax_Handler extends WP_Ajax_UnitTestCase {

    /**
     * Admin user ID.
     *
     * @var int
     */
    private $admin_id;

    /**
     * Subscriber user ID.
     *
     * @var int
     */
    private $subscriber_id;

    /**
     * Set up test fixtures.
     */
    public function set_up() {
        parent::set_up();

        // Create users
        $this->admin_id = $this->factory->user->create(['role' => 'administrator']);
        $this->subscriber_id = $this->factory->user->create(['role' => 'subscriber']);

        // Initialize the handler
        new MLF_Ajax_Handler();
    }

    /**
     * Clean up after tests.
     */
    public function tear_down() {
        // Clean up test fonts
        $fonts = get_posts([
            'post_type'      => 'wp_font_family',
            'posts_per_page' => -1,
            'meta_key'       => '_mlf_imported',
            'meta_value'     => '1',
            'fields'         => 'ids',
        ]);

        foreach ($fonts as $font_id) {
            wp_delete_post($font_id, true);
        }

        wp_set_current_user(0);
        delete_transient('mlf_imported_fonts_list');

        parent::tear_down();
    }

    /**
     * Test download without nonce.
     */
    public function test_download_without_nonce() {
        wp_set_current_user($this->admin_id);

        $_POST['font_name'] = 'Open Sans';
        $_POST['weights'] = [400];
        $_POST['styles'] = ['normal'];

        $this->expectException('WPAjaxDieStopException');

        try {
            $this->_handleAjax('mlf_download_font');
        } catch (WPAjaxDieStopException $e) {
            $response = json_decode($this->_last_response, true);
            $this->assertFalse($response['success']);
            $this->assertStringContainsString('Security', $response['data']['message']);
            throw $e;
        }
    }

    /**
     * Test download with invalid nonce.
     */
    public function test_download_with_invalid_nonce() {
        wp_set_current_user($this->admin_id);

        $_POST['nonce'] = 'invalid_nonce';
        $_POST['font_name'] = 'Open Sans';
        $_POST['weights'] = [400];
        $_POST['styles'] = ['normal'];

        $this->expectException('WPAjaxDieStopException');

        try {
            $this->_handleAjax('mlf_download_font');
        } catch (WPAjaxDieStopException $e) {
            $response = json_decode($this->_last_response, true);
            $this->assertFalse($response['success']);
            throw $e;
        }
    }

    /**
     * Test download without proper capability.
     */
    public function test_download_without_capability() {
        wp_set_current_user($this->subscriber_id);

        $_POST['nonce'] = wp_create_nonce('mlf_download_font');
        $_POST['font_name'] = 'Open Sans';
        $_POST['weights'] = [400];
        $_POST['styles'] = ['normal'];

        $this->expectException('WPAjaxDieStopException');

        try {
            $this->_handleAjax('mlf_download_font');
        } catch (WPAjaxDieStopException $e) {
            $response = json_decode($this->_last_response, true);
            $this->assertFalse($response['success']);
            $this->assertStringContainsString('Unauthorized', $response['data']['message']);
            throw $e;
        }
    }

    /**
     * Test download with empty font name.
     */
    public function test_download_empty_font_name() {
        wp_set_current_user($this->admin_id);

        $_POST['nonce'] = wp_create_nonce('mlf_download_font');
        $_POST['font_name'] = '';
        $_POST['weights'] = [400];
        $_POST['styles'] = ['normal'];

        $this->expectException('WPAjaxDieStopException');

        try {
            $this->_handleAjax('mlf_download_font');
        } catch (WPAjaxDieStopException $e) {
            $response = json_decode($this->_last_response, true);
            $this->assertFalse($response['success']);
            $this->assertStringContainsString('required', $response['data']['message']);
            throw $e;
        }
    }

    /**
     * Test download with invalid font name (XSS attempt).
     */
    public function test_download_invalid_font_name_xss() {
        wp_set_current_user($this->admin_id);

        $_POST['nonce'] = wp_create_nonce('mlf_download_font');
        $_POST['font_name'] = '<script>alert("xss")</script>';
        $_POST['weights'] = [400];
        $_POST['styles'] = ['normal'];

        $this->expectException('WPAjaxDieStopException');

        try {
            $this->_handleAjax('mlf_download_font');
        } catch (WPAjaxDieStopException $e) {
            $response = json_decode($this->_last_response, true);
            $this->assertFalse($response['success']);
            $this->assertStringContainsString('Invalid font name', $response['data']['message']);
            throw $e;
        }
    }

    /**
     * Test download with path traversal in font name.
     */
    public function test_download_path_traversal() {
        wp_set_current_user($this->admin_id);

        $_POST['nonce'] = wp_create_nonce('mlf_download_font');
        $_POST['font_name'] = '../../../etc/passwd';
        $_POST['weights'] = [400];
        $_POST['styles'] = ['normal'];

        $this->expectException('WPAjaxDieStopException');

        try {
            $this->_handleAjax('mlf_download_font');
        } catch (WPAjaxDieStopException $e) {
            $response = json_decode($this->_last_response, true);
            $this->assertFalse($response['success']);
            $this->assertStringContainsString('Invalid font name', $response['data']['message']);
            throw $e;
        }
    }

    /**
     * Test download with font name too long.
     */
    public function test_download_font_name_too_long() {
        wp_set_current_user($this->admin_id);

        $_POST['nonce'] = wp_create_nonce('mlf_download_font');
        $_POST['font_name'] = str_repeat('a', 101);
        $_POST['weights'] = [400];
        $_POST['styles'] = ['normal'];

        $this->expectException('WPAjaxDieStopException');

        try {
            $this->_handleAjax('mlf_download_font');
        } catch (WPAjaxDieStopException $e) {
            $response = json_decode($this->_last_response, true);
            $this->assertFalse($response['success']);
            $this->assertStringContainsString('too long', $response['data']['message']);
            throw $e;
        }
    }

    /**
     * Test download with no weights.
     */
    public function test_download_no_weights() {
        wp_set_current_user($this->admin_id);

        $_POST['nonce'] = wp_create_nonce('mlf_download_font');
        $_POST['font_name'] = 'Open Sans';
        $_POST['weights'] = [];
        $_POST['styles'] = ['normal'];

        $this->expectException('WPAjaxDieStopException');

        try {
            $this->_handleAjax('mlf_download_font');
        } catch (WPAjaxDieStopException $e) {
            $response = json_decode($this->_last_response, true);
            $this->assertFalse($response['success']);
            $this->assertStringContainsString('weight', $response['data']['message']);
            throw $e;
        }
    }

    /**
     * Test download with invalid weights.
     */
    public function test_download_invalid_weights() {
        wp_set_current_user($this->admin_id);

        $_POST['nonce'] = wp_create_nonce('mlf_download_font');
        $_POST['font_name'] = 'Open Sans';
        $_POST['weights'] = [999, 1000]; // Invalid weights
        $_POST['styles'] = ['normal'];

        $this->expectException('WPAjaxDieStopException');

        try {
            $this->_handleAjax('mlf_download_font');
        } catch (WPAjaxDieStopException $e) {
            $response = json_decode($this->_last_response, true);
            $this->assertFalse($response['success']);
            $this->assertStringContainsString('weight', $response['data']['message']);
            throw $e;
        }
    }

    /**
     * Test download with no styles.
     */
    public function test_download_no_styles() {
        wp_set_current_user($this->admin_id);

        $_POST['nonce'] = wp_create_nonce('mlf_download_font');
        $_POST['font_name'] = 'Open Sans';
        $_POST['weights'] = [400];
        $_POST['styles'] = [];

        $this->expectException('WPAjaxDieStopException');

        try {
            $this->_handleAjax('mlf_download_font');
        } catch (WPAjaxDieStopException $e) {
            $response = json_decode($this->_last_response, true);
            $this->assertFalse($response['success']);
            $this->assertStringContainsString('style', $response['data']['message']);
            throw $e;
        }
    }

    /**
     * Test delete without nonce.
     */
    public function test_delete_without_nonce() {
        wp_set_current_user($this->admin_id);

        $font_id = $this->create_test_font();
        $_POST['font_id'] = $font_id;

        $this->expectException('WPAjaxDieStopException');

        try {
            $this->_handleAjax('mlf_delete_font');
        } catch (WPAjaxDieStopException $e) {
            $response = json_decode($this->_last_response, true);
            $this->assertFalse($response['success']);
            throw $e;
        }
    }

    /**
     * Test delete without capability.
     */
    public function test_delete_without_capability() {
        wp_set_current_user($this->subscriber_id);

        $font_id = $this->create_test_font();
        $_POST['nonce'] = wp_create_nonce('mlf_delete_font');
        $_POST['font_id'] = $font_id;

        $this->expectException('WPAjaxDieStopException');

        try {
            $this->_handleAjax('mlf_delete_font');
        } catch (WPAjaxDieStopException $e) {
            $response = json_decode($this->_last_response, true);
            $this->assertFalse($response['success']);
            $this->assertStringContainsString('Unauthorized', $response['data']['message']);
            throw $e;
        }
    }

    /**
     * Test delete with invalid font ID.
     */
    public function test_delete_invalid_font_id() {
        wp_set_current_user($this->admin_id);

        $_POST['nonce'] = wp_create_nonce('mlf_delete_font');
        $_POST['font_id'] = 0;

        $this->expectException('WPAjaxDieStopException');

        try {
            $this->_handleAjax('mlf_delete_font');
        } catch (WPAjaxDieStopException $e) {
            $response = json_decode($this->_last_response, true);
            $this->assertFalse($response['success']);
            $this->assertStringContainsString('Invalid', $response['data']['message']);
            throw $e;
        }
    }

    /**
     * Test delete font not found.
     */
    public function test_delete_font_not_found() {
        wp_set_current_user($this->admin_id);

        $_POST['nonce'] = wp_create_nonce('mlf_delete_font');
        $_POST['font_id'] = 99999;

        $this->expectException('WPAjaxDieStopException');

        try {
            $this->_handleAjax('mlf_delete_font');
        } catch (WPAjaxDieStopException $e) {
            $response = json_decode($this->_last_response, true);
            $this->assertFalse($response['success']);
            $this->assertStringContainsString('not found', $response['data']['message']);
            throw $e;
        }
    }

    /**
     * Test delete font not imported by plugin.
     */
    public function test_delete_font_not_ours() {
        wp_set_current_user($this->admin_id);

        // Create font without our meta
        $font_id = wp_insert_post([
            'post_type'   => 'wp_font_family',
            'post_title'  => 'Theme Font',
            'post_status' => 'publish',
        ]);

        $_POST['nonce'] = wp_create_nonce('mlf_delete_font');
        $_POST['font_id'] = $font_id;

        $this->expectException('WPAjaxDieStopException');

        try {
            $this->_handleAjax('mlf_delete_font');
        } catch (WPAjaxDieStopException $e) {
            $response = json_decode($this->_last_response, true);
            $this->assertFalse($response['success']);
            $this->assertStringContainsString('not imported', $response['data']['message']);
            throw $e;
        }

        // Clean up
        wp_delete_post($font_id, true);
    }

    /**
     * Helper to create a test font.
     *
     * @return int Font ID.
     */
    private function create_test_font() {
        $font_id = wp_insert_post([
            'post_type'   => 'wp_font_family',
            'post_title'  => 'Test Font',
            'post_name'   => 'test-font',
            'post_status' => 'publish',
        ]);

        update_post_meta($font_id, '_mlf_imported', '1');

        return $font_id;
    }
}
