<?php
/**
 * Tests for WPAW_Model_Registry
 *
 * @package WP_Agentic_Writer
 */

/**
 * Test case for WPAW_Model_Registry.
 */
class Test_Model_Registry extends PHPUnit\Framework\TestCase
{
    /**
     * Test that get_registry returns a non-empty array.
     */
    public function testGetRegistryReturnsArray()
    {
        $registry = WPAW_Model_Registry::get_registry();
        $this->assertIsArray($registry);
        $this->assertNotEmpty($registry);
    }

    /**
     * Test that all task defaults return valid model IDs.
     */
    public function testTaskDefaultsReturnValidModelIds()
    {
        $defaults = WPAW_Model_Registry::get_task_defaults();

        $this->assertIsArray($defaults);

        // Expected task types
        $expectedTasks = [
            "chat",
            "clarity",
            "planning",
            "writing",
            "execution",
            "refinement",
            "analysis",
            "summarize",
            "image",
        ];

        foreach ($expectedTasks as $task) {
            $this->assertArrayHasKey($task, $defaults, "Missing task: $task");
            $this->assertNotEmpty(
                $defaults[$task],
                "Empty default for task: $task",
            );
            $this->assertIsString(
                $defaults[$task],
                "Default must be string for task: $task",
            );
        }
    }

    /**
     * Test that get_default_model returns valid model IDs.
     */
    public function testGetDefaultModelReturnsValidId()
    {
        $tasks = [
            WPAW_Model_Registry::TASK_CHAT,
            WPAW_Model_Registry::TASK_CLARITY,
            WPAW_Model_Registry::TASK_PLANNING,
            WPAW_Model_Registry::TASK_WRITING,
            WPAW_Model_Registry::TASK_EXECUTION,
            WPAW_Model_Registry::TASK_REFINEMENT,
            WPAW_Model_Registry::TASK_ANALYSIS,
            WPAW_Model_Registry::TASK_SUMMARIZE,
            WPAW_Model_Registry::TASK_IMAGE,
        ];

        foreach ($tasks as $task) {
            $model = WPAW_Model_Registry::get_default_model($task);
            $this->assertNotEmpty($model, "Empty model for task: $task");
            $this->assertIsString(
                $model,
                "Model must be string for task: $task",
            );
            // Model IDs should contain a slash (provider/model format)
            $this->assertStringContainsString(
                "/",
                $model,
                "Invalid model ID format for task: $task",
            );
        }
    }

    /**
     * Test fallback model resolution.
     */
    public function testFallbackModelResolvesCorrectly()
    {
        // Known tasks with fallbacks
        $tasks = ["chat", "writing", "refinement", "image"];

        foreach ($tasks as $task) {
            $fallback = WPAW_Model_Registry::get_fallback_model($task);
            $default = WPAW_Model_Registry::get_default_model($task);

            $this->assertNotEmpty($fallback, "Empty fallback for task: $task");
            // Fallback should be different from default (or same if only one model exists)
            $this->assertIsString(
                $fallback,
                "Fallback must be string for task: $task",
            );
        }
    }

    /**
     * Test unknown task falls back to chat defaults.
     */
    public function testUnknownTaskFallsBackToChat()
    {
        $unknownTask = "unknown_task_xyz";
        $chatDefault = WPAW_Model_Registry::get_default_model("chat");

        $model = WPAW_Model_Registry::get_default_model($unknownTask);
        $fallback = WPAW_Model_Registry::get_fallback_model($unknownTask);

        $this->assertEquals(
            $chatDefault,
            $model,
            "Unknown task should fall back to chat default",
        );
        $this->assertEquals(
            $chatDefault,
            $fallback,
            "Unknown task fallback should also be chat default",
        );
    }

    /**
     * Test model validation.
     */
    public function testIsValidModel()
    {
        // Valid models from registry
        $this->assertTrue(
            WPAW_Model_Registry::is_valid_model("google/gemini-2.5-flash"),
            "gemini-2.5-flash should be valid",
        );
        $this->assertTrue(
            WPAW_Model_Registry::is_valid_model("anthropic/claude-3.5-haiku"),
            "claude-3.5-haiku should be valid",
        );
        $this->assertTrue(
            WPAW_Model_Registry::is_valid_model("google/gemini-2.0-flash-exp"),
            "gemini-2.0-flash-exp fallback should be valid",
        );

        // Invalid models
        $this->assertFalse(
            WPAW_Model_Registry::is_valid_model("nonexistent/model"),
            "Unknown model should be invalid",
        );
        $this->assertFalse(
            WPAW_Model_Registry::is_valid_model(""),
            "Empty model should be invalid",
        );
    }

    /**
     * Test model display name generation.
     */
    public function testGetModelDisplayName()
    {
        // Known display names
        $this->assertEquals(
            "Google Gemini 2.5 Flash",
            WPAW_Model_Registry::get_model_display_name(
                "google/gemini-2.5-flash",
            ),
        );
        $this->assertEquals(
            "Anthropic Claude 3.5 Haiku",
            WPAW_Model_Registry::get_model_display_name(
                "anthropic/claude-3.5-haiku",
            ),
        );

        // Generated display names
        $displayName = WPAW_Model_Registry::get_model_display_name(
            "provider/test-model-v2",
        );
        $this->assertNotEmpty($displayName);
        $this->assertIsString($displayName);
        // Should capitalize provider and model
        $this->assertStringContainsString("Provider", $displayName);
        $this->assertStringContainsString("Test", $displayName);
    }

    /**
     * Test empty model ID returns Unknown Model.
     */
    public function testEmptyModelDisplayName()
    {
        $this->assertEquals(
            "Unknown Model",
            WPAW_Model_Registry::get_model_display_name(""),
        );
    }

    /**
     * Test activation defaults format.
     */
    public function testGetActivationDefaults()
    {
        $defaults = WPAW_Model_Registry::get_activation_defaults();

        $this->assertIsArray($defaults);
        $this->assertArrayHasKey("planning_model", $defaults);
        $this->assertArrayHasKey("execution_model", $defaults);
        $this->assertArrayHasKey("image_model", $defaults);

        // Should return valid model IDs
        $this->assertNotEmpty($defaults["planning_model"]);
        $this->assertNotEmpty($defaults["execution_model"]);
        $this->assertNotEmpty($defaults["image_model"]);
    }

    /**
     * Test frontend data format.
     */
    public function testGetFrontendData()
    {
        $data = WPAW_Model_Registry::get_frontend_data();

        $this->assertIsArray($data);
        $this->assertNotEmpty($data);

        // Should have default and label for each task
        foreach ($data as $task => $taskData) {
            $this->assertArrayHasKey(
                "default",
                $taskData,
                "Missing 'default' for task: $task",
            );
            $this->assertArrayHasKey(
                "label",
                $taskData,
                "Missing 'label' for task: $task",
            );
            $this->assertNotEmpty($taskData["default"]);
            $this->assertNotEmpty($taskData["label"]);
        }
    }

    /**
     * Test image_models are present in registry.
     */
    public function testImageModelsInRegistry()
    {
        $registry = WPAW_Model_Registry::get_registry();

        $this->assertArrayHasKey("image_models", $registry);
        $this->assertIsArray($registry["image_models"]);
        $this->assertNotEmpty($registry["image_models"]);

        // Each image model should have a display name
        foreach ($registry["image_models"] as $modelId => $displayName) {
            $this->assertIsString($modelId);
            $this->assertIsString($displayName);
            $this->assertNotEmpty($displayName);
        }
    }
}
