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

/**
 * Class Test_MLF_Rest_Controller
 *
 * @covers MLF_Rest_Controller
 */
class Test_MLF_Rest_Controller extends WP_Test_REST_Controller_Testcase {

    /**
     * REST controller instance.
     *
     * @var MLF_Rest_Controller
     */
    private $controller;

    /**
     * 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();

        // Register REST routes
        $this->controller = new MLF_Rest_Controller();
        $this->controller->register_routes();

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

        // Clear any existing fonts and cache
        delete_transient('mlf_imported_fonts_list');
    }

    /**
     * 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 route registration.
     */
    public function test_register_routes() {
        $routes = rest_get_server()->get_routes();

        $this->assertArrayHasKey('/mlf/v1/fonts', $routes);
        $this->assertArrayHasKey('/mlf/v1/fonts/(?P<id>[\d]+)', $routes);
    }

    /**
     * Test get_items without authentication.
     */
    public function test_get_items_unauthenticated() {
        $request = new WP_REST_Request('GET', '/mlf/v1/fonts');
        $response = rest_get_server()->dispatch($request);

        $this->assertEquals(401, $response->get_status());
    }

    /**
     * Test get_items with subscriber (insufficient permissions).
     */
    public function test_get_items_insufficient_permissions() {
        wp_set_current_user($this->subscriber_id);

        $request = new WP_REST_Request('GET', '/mlf/v1/fonts');
        $response = rest_get_server()->dispatch($request);

        $this->assertEquals(403, $response->get_status());
    }

    /**
     * Test get_items with admin.
     */
    public function test_get_items_as_admin() {
        wp_set_current_user($this->admin_id);

        $request = new WP_REST_Request('GET', '/mlf/v1/fonts');
        $response = rest_get_server()->dispatch($request);

        $this->assertEquals(200, $response->get_status());
        $this->assertIsArray($response->get_data());
    }

    /**
     * Test get_items returns installed fonts.
     */
    public function test_get_items_returns_fonts() {
        wp_set_current_user($this->admin_id);

        // Create a test font
        $font_id = $this->create_test_font('Test API Font', 'test-api-font');

        $request = new WP_REST_Request('GET', '/mlf/v1/fonts');
        $response = rest_get_server()->dispatch($request);

        $this->assertEquals(200, $response->get_status());
        $data = $response->get_data();
        $this->assertCount(1, $data);
        $this->assertEquals($font_id, $data[0]['id']);
        $this->assertEquals('Test API Font', $data[0]['name']);
    }

    /**
     * Test get_item.
     */
    public function test_get_item() {
        wp_set_current_user($this->admin_id);

        $font_id = $this->create_test_font('Single Font', 'single-font');

        $request = new WP_REST_Request('GET', '/mlf/v1/fonts/' . $font_id);
        $response = rest_get_server()->dispatch($request);

        $this->assertEquals(200, $response->get_status());
        $data = $response->get_data();
        $this->assertEquals($font_id, $data['id']);
        $this->assertEquals('Single Font', $data['name']);
    }

    /**
     * Test get_item not found.
     */
    public function test_get_item_not_found() {
        wp_set_current_user($this->admin_id);

        $request = new WP_REST_Request('GET', '/mlf/v1/fonts/99999');
        $response = rest_get_server()->dispatch($request);

        $this->assertEquals(404, $response->get_status());
    }

    /**
     * Test create_item without authentication.
     */
    public function test_create_item_unauthenticated() {
        $request = new WP_REST_Request('POST', '/mlf/v1/fonts');
        $request->set_param('font_name', 'Open Sans');
        $request->set_param('weights', [400, 700]);
        $request->set_param('styles', ['normal']);

        $response = rest_get_server()->dispatch($request);

        $this->assertEquals(401, $response->get_status());
    }

    /**
     * Test create_item with subscriber.
     */
    public function test_create_item_insufficient_permissions() {
        wp_set_current_user($this->subscriber_id);

        $request = new WP_REST_Request('POST', '/mlf/v1/fonts');
        $request->set_param('font_name', 'Open Sans');
        $request->set_param('weights', [400, 700]);
        $request->set_param('styles', ['normal']);

        $response = rest_get_server()->dispatch($request);

        $this->assertEquals(403, $response->get_status());
    }

    /**
     * Test create_item with invalid font name.
     */
    public function test_create_item_invalid_font_name() {
        wp_set_current_user($this->admin_id);

        $request = new WP_REST_Request('POST', '/mlf/v1/fonts');
        $request->set_param('font_name', '<script>alert("xss")</script>');
        $request->set_param('weights', [400]);
        $request->set_param('styles', ['normal']);

        $response = rest_get_server()->dispatch($request);

        $this->assertEquals(400, $response->get_status());
    }

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

        $request = new WP_REST_Request('POST', '/mlf/v1/fonts');
        $request->set_param('font_name', 'Test Font');
        $request->set_param('weights', []);
        $request->set_param('styles', ['normal']);

        $response = rest_get_server()->dispatch($request);

        $this->assertEquals(400, $response->get_status());
    }

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

        $request = new WP_REST_Request('POST', '/mlf/v1/fonts');
        $request->set_param('font_name', 'Test Font');
        $request->set_param('weights', [400]);
        $request->set_param('styles', []);

        $response = rest_get_server()->dispatch($request);

        $this->assertEquals(400, $response->get_status());
    }

    /**
     * Test delete_item without authentication.
     */
    public function test_delete_item_unauthenticated() {
        $font_id = $this->create_test_font('Delete Font', 'delete-font');

        $request = new WP_REST_Request('DELETE', '/mlf/v1/fonts/' . $font_id);
        $response = rest_get_server()->dispatch($request);

        $this->assertEquals(401, $response->get_status());
    }

    /**
     * Test delete_item with subscriber.
     */
    public function test_delete_item_insufficient_permissions() {
        $font_id = $this->create_test_font('Delete Font 2', 'delete-font-2');

        wp_set_current_user($this->subscriber_id);

        $request = new WP_REST_Request('DELETE', '/mlf/v1/fonts/' . $font_id);
        $response = rest_get_server()->dispatch($request);

        $this->assertEquals(403, $response->get_status());
    }

    /**
     * Test delete_item as admin.
     */
    public function test_delete_item_as_admin() {
        $font_id = $this->create_test_font('Delete Font 3', 'delete-font-3');

        wp_set_current_user($this->admin_id);

        $request = new WP_REST_Request('DELETE', '/mlf/v1/fonts/' . $font_id);
        $response = rest_get_server()->dispatch($request);

        $this->assertEquals(200, $response->get_status());
        $data = $response->get_data();
        $this->assertTrue($data['deleted']);
    }

    /**
     * Test delete_item not found.
     */
    public function test_delete_item_not_found() {
        wp_set_current_user($this->admin_id);

        $request = new WP_REST_Request('DELETE', '/mlf/v1/fonts/99999');
        $response = rest_get_server()->dispatch($request);

        $this->assertEquals(404, $response->get_status());
    }

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

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

        $request = new WP_REST_Request('DELETE', '/mlf/v1/fonts/' . $font_id);
        $response = rest_get_server()->dispatch($request);

        $this->assertEquals(403, $response->get_status());

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

    /**
     * Test item schema.
     */
    public function test_get_item_schema() {
        $request = new WP_REST_Request('OPTIONS', '/mlf/v1/fonts');
        $response = rest_get_server()->dispatch($request);
        $data = $response->get_data();

        $this->assertArrayHasKey('schema', $data);
        $this->assertEquals('font', $data['schema']['title']);
    }

    /**
     * Test context parameter.
     */
    public function test_context_param() {
        // This test is inherited from WP_Test_REST_Controller_Testcase
        // We just need to implement it to satisfy the abstract requirement
        $this->assertTrue(true);
    }

    /**
     * Helper to create a test font.
     *
     * @param string $name Font name.
     * @param string $slug Font slug.
     * @return int Font ID.
     */
    private function create_test_font($name, $slug) {
        // Create font family post
        $font_id = wp_insert_post([
            'post_type'   => 'wp_font_family',
            'post_title'  => $name,
            'post_name'   => $slug,
            'post_status' => 'publish',
            'post_content' => wp_json_encode([
                'fontFamily' => $name,
                'slug'       => $slug,
            ]),
        ]);

        // Add our meta marker
        update_post_meta($font_id, '_mlf_imported', '1');

        // Create a font face
        $face_id = wp_insert_post([
            'post_type'   => 'wp_font_face',
            'post_title'  => $name . ' 400 normal',
            'post_status' => 'publish',
            'post_parent' => $font_id,
            'post_content' => wp_json_encode([
                'fontFamily' => $name,
                'fontWeight' => '400',
                'fontStyle'  => 'normal',
                'src'        => ['file:./fonts/' . $slug . '_normal_400.woff2'],
            ]),
        ]);

        // Clear cache
        delete_transient('mlf_imported_fonts_list');

        return $font_id;
    }
}
