<?php

namespace TbiBank\FusionPay\Test\Unit\Setup\Patch\Schema;

use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\DB\Ddl\Table;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use PHPUnit\Framework\TestCase;
use TbiBank\FusionPay\Setup\Patch\Schema\AddTbiStatusColumn;
use TbiBank\FusionPay\Setup\Patch\Schema\AddTbiStatusColumnToOrderGrid;

/**
 * Behaviour under test: TbiBank\FusionPay\Setup\Patch\Schema\AddTbiStatusColumnToOrderGrid
 *
 * This is the schema half of the CKT-3844 denormalization: `sales_order_grid.tbi_status` is
 * added so the admin grid can read it directly, instead of the deleted
 * AddTbiStatusToOrderGridCollection plugin computing it via a runtime JOIN on every grid load.
 *
 * Given a store where 'sales_order_grid' does not yet have a 'tbi_status' column
 * When  the patch is applied
 * Then  the column is added: nullable (unlike sales_order.tbi_status, which is NOT NULL with a
 *       default — see AddTbiStatusColumn — this one must tolerate non-FusionPay orders, whose
 *       grid rows should stay blank rather than being forced into a FusionPay-specific default).
 */
class AddTbiStatusColumnToOrderGridTest extends TestCase
{
    public function testAddsNullableTbiStatusColumnToOrderGridWhenMissing(): void
    {
        $connection = $this->createMock(AdapterInterface::class);
        $connection->method('tableColumnExists')->with('sales_order_grid', 'tbi_status')->willReturn(false);

        $addedColumn = null;
        $connection->expects($this->once())
            ->method('addColumn')
            ->with('sales_order_grid', 'tbi_status', $this->callback(function ($definition) use (&$addedColumn) {
                $addedColumn = $definition;
                return true;
            }));

        $setup = $this->createMock(ModuleDataSetupInterface::class);
        $setup->method('getConnection')->willReturn($connection);
        $setup->method('getTable')->willReturnArgument(0);
        $setup->expects($this->once())->method('startSetup');
        $setup->expects($this->once())->method('endSetup');

        (new AddTbiStatusColumnToOrderGrid($setup))->apply();

        $this->assertSame(Table::TYPE_TEXT, $addedColumn['type']);
        $this->assertSame(255, $addedColumn['length']);
        $this->assertTrue($addedColumn['nullable'], 'grid column must stay nullable for non-FusionPay orders');
    }

    /**
     * Given 'sales_order_grid.tbi_status' already exists (patch re-run / already-migrated store)
     * When  the patch is applied
     * Then  it does NOT attempt to add the column again — patches must be safely re-runnable.
     */
    public function testIsIdempotentWhenColumnAlreadyExists(): void
    {
        $connection = $this->createMock(AdapterInterface::class);
        $connection->method('tableColumnExists')->willReturn(true);
        $connection->expects($this->never())->method('addColumn');

        $setup = $this->createMock(ModuleDataSetupInterface::class);
        $setup->method('getConnection')->willReturn($connection);
        $setup->method('getTable')->willReturnArgument(0);

        (new AddTbiStatusColumnToOrderGrid($setup))->apply();
    }

    /**
     * This schema patch must run strictly after AddTbiStatusColumn (which adds the equivalent
     * column to 'sales_order') — declaring that dependency is what guarantees patch ordering
     * regardless of how Magento schedules schema patches within a module.
     */
    public function testDeclaresDependencyOnAddTbiStatusColumn(): void
    {
        $this->assertSame([AddTbiStatusColumn::class], AddTbiStatusColumnToOrderGrid::getDependencies());
    }
}
