<?php
namespace Tests\Unit\admin\Controllers;

use PHPUnit\Framework\TestCase;
use admin\Controllers\ShopProductController;
use Domain\Product\ProductRepository;
use Domain\Integrations\IntegrationsRepository;
use Domain\Languages\LanguagesRepository;

class ShopProductControllerTest extends TestCase
{
    private $repository;
    private $integrationsRepository;
    private $languagesRepository;
    private $controller;

    protected function setUp(): void
    {
        $this->repository = $this->createMock(ProductRepository::class);
        $this->integrationsRepository = $this->createMock(IntegrationsRepository::class);
        $this->languagesRepository = $this->createMock(LanguagesRepository::class);
        $this->controller = new ShopProductController($this->repository, $this->integrationsRepository, $this->languagesRepository);
    }

    public function testConstructorAcceptsRepositories(): void
    {
        $controller = new ShopProductController($this->repository, $this->integrationsRepository, $this->languagesRepository);
        $this->assertInstanceOf(ShopProductController::class, $controller);
    }

    public function testHasMassEditActionMethods(): void
    {
        $this->assertTrue(method_exists($this->controller, 'mass_edit'));
        $this->assertTrue(method_exists($this->controller, 'mass_edit_save'));
        $this->assertTrue(method_exists($this->controller, 'get_products_by_category'));
    }

    public function testHasViewListMethods(): void
    {
        $this->assertTrue(method_exists($this->controller, 'view_list'));
    }

    public function testHasEditAndSaveMethods(): void
    {
        $this->assertTrue(method_exists($this->controller, 'product_edit'));
        $this->assertTrue(method_exists($this->controller, 'save'));
    }

    public function testHasOperationMethods(): void
    {
        $this->assertTrue(method_exists($this->controller, 'duplicate_product'));
        $this->assertTrue(method_exists($this->controller, 'product_archive'));
        $this->assertTrue(method_exists($this->controller, 'product_unarchive'));
        $this->assertTrue(method_exists($this->controller, 'product_delete'));
        $this->assertTrue(method_exists($this->controller, 'change_product_status'));
        $this->assertTrue(method_exists($this->controller, 'product_change_price_brutto'));
        $this->assertTrue(method_exists($this->controller, 'product_change_price_brutto_promo'));
        $this->assertTrue(method_exists($this->controller, 'product_change_custom_label'));
        $this->assertTrue(method_exists($this->controller, 'product_custom_label_suggestions'));
        $this->assertTrue(method_exists($this->controller, 'product_custom_label_save'));
        $this->assertTrue(method_exists($this->controller, 'ajax_product_url'));
        $this->assertTrue(method_exists($this->controller, 'generate_sku_code'));
    }

    public function testHasCombinationMethods(): void
    {
        $this->assertTrue(method_exists($this->controller, 'product_combination'));
        $this->assertTrue(method_exists($this->controller, 'generate_combination'));
        $this->assertTrue(method_exists($this->controller, 'delete_combination'));
        $this->assertTrue(method_exists($this->controller, 'delete_combination_ajax'));
        $this->assertTrue(method_exists($this->controller, 'product_combination_stock_0_buy_save'));
        $this->assertTrue(method_exists($this->controller, 'product_combination_sku_save'));
        $this->assertTrue(method_exists($this->controller, 'product_combination_quantity_save'));
        $this->assertTrue(method_exists($this->controller, 'product_combination_price_save'));
    }

    public function testHasImageAndFileMethods(): void
    {
        $this->assertTrue(method_exists($this->controller, 'image_delete'));
        $this->assertTrue(method_exists($this->controller, 'images_order_save'));
        $this->assertTrue(method_exists($this->controller, 'image_alt_change'));
        $this->assertTrue(method_exists($this->controller, 'product_file_delete'));
        $this->assertTrue(method_exists($this->controller, 'product_file_name_change'));
        $this->assertTrue(method_exists($this->controller, 'product_image_delete'));
    }

    public function testMassEditReturnsString(): void
    {
        $reflection = new \ReflectionClass($this->controller);
        $this->assertEquals('string', (string)$reflection->getMethod('mass_edit')->getReturnType());
    }

    public function testMassEditSaveReturnsVoid(): void
    {
        $reflection = new \ReflectionClass($this->controller);
        $this->assertEquals('void', (string)$reflection->getMethod('mass_edit_save')->getReturnType());
    }

    public function testGetProductsByCategoryReturnsVoid(): void
    {
        $reflection = new \ReflectionClass($this->controller);
        $this->assertEquals('void', (string)$reflection->getMethod('get_products_by_category')->getReturnType());
    }

    public function testConstructorRequiresRepositories(): void
    {
        $reflection = new \ReflectionClass(ShopProductController::class);
        $constructor = $reflection->getConstructor();
        $params = $constructor->getParameters();

        $this->assertCount(3, $params);
        $this->assertEquals('Domain\Product\ProductRepository', $params[0]->getType()->getName());
        $this->assertEquals('Domain\Integrations\IntegrationsRepository', $params[1]->getType()->getName());
        $this->assertEquals('Domain\Languages\LanguagesRepository', $params[2]->getType()->getName());
    }

    public function testHasFormBuildingHelpers(): void
    {
        $reflection = new \ReflectionClass(ShopProductController::class);

        $expectedPrivate = [
            'buildProductFormViewModel',
            'renderSkuField',
            'renderCategoriesTree',
            'renderGalleryBox',
            'renderFilesBox',
            'renderRelatedProducts',
            'renderCustomFieldsBox',
            'escapeHtml',
            'resolveSavePayload',
        ];

        foreach ($expectedPrivate as $method) {
            $this->assertTrue(
                $reflection->hasMethod($method),
                "Missing private method: {$method}"
            );
            $this->assertTrue(
                $reflection->getMethod($method)->isPrivate(),
                "Method {$method} should be private"
            );
        }
    }

    public function testSaveMethodReturnsVoid(): void
    {
        $reflection = new \ReflectionClass($this->controller);
        $this->assertEquals('void', (string)$reflection->getMethod('save')->getReturnType());
    }
}
