<?php

namespace yiiunit\extensions\sphinx;

use yii\db\DataReader;

/**
 * @group sphinx
 */
class CommandTest extends SphinxTestCase
{
    protected function tearDown()
    {
        $this->truncateRuntimeIndex('yii2_test_rt_index');
        parent::tearDown();
    }

    // Tests :

    public function testConstruct()
    {
        $db = $this->getConnection(false);

        // null
        $command = $db->createCommand();
        $this->assertEquals(null, $command->sql);

        // string
        $sql = 'SELECT * FROM yii2_test_item_index';
        $params = [
            'name' => 'value'
        ];
        $command = $db->createCommand($sql, $params);
        $this->assertEquals($sql, $command->sql);
        $this->assertEquals($params, $command->params);
    }

    public function testGetSetSql()
    {
        $db = $this->getConnection(false);

        $sql = 'SELECT * FROM yii2_test_item_index';
        $command = $db->createCommand($sql);
        $this->assertEquals($sql, $command->sql);

        $sql2 = 'SELECT * FROM yii2_test_item_index';
        $command->sql = $sql2;
        $this->assertEquals($sql2, $command->sql);
    }

    public function testAutoQuoting()
    {
        $db = $this->getConnection(false);

        $sql = 'SELECT [[id]], [[t.name]] FROM {{yii2_test_item_index}} t';
        $command = $db->createCommand($sql);
        $this->assertEquals("SELECT `id`, `t`.`name` FROM `yii2_test_item_index` t", $command->sql);
    }

    public function testPrepareCancel()
    {
        $db = $this->getConnection(false);

        $command = $db->createCommand('SELECT * FROM yii2_test_item_index');
        $this->assertEquals(null, $command->pdoStatement);
        $command->prepare();
        $this->assertNotEquals(null, $command->pdoStatement);
        $command->cancel();
        $this->assertEquals(null, $command->pdoStatement);
    }

    public function testExecute()
    {
        $db = $this->getConnection();

        $sql = 'SELECT COUNT(*) FROM yii2_test_item_index WHERE MATCH(\'wooden\')';
        $command = $db->createCommand($sql);
        $this->assertEquals(1, $command->queryScalar());

        $command = $db->createCommand('bad SQL');
        $this->setExpectedException('\yii\db\Exception');
        $command->execute();
    }

    public function testQuery()
    {
        $db = $this->getConnection();

        // query
        $sql = 'SELECT * FROM yii2_test_item_index';
        $reader = $db->createCommand($sql)->query();
        $this->assertTrue($reader instanceof DataReader);

        // queryAll
        $rows = $db->createCommand('SELECT * FROM yii2_test_item_index')->queryAll();
        $this->assertEquals(2, count($rows));
        $row = $rows[1];
        $this->assertEquals(2, $row['id']);
        $this->assertEquals(2, $row['category_id']);

        $rows = $db->createCommand('SELECT * FROM yii2_test_item_index WHERE id=10')->queryAll();
        $this->assertEquals([], $rows);

        // queryOne
        $sql = 'SELECT * FROM yii2_test_item_index ORDER BY id ASC';
        $row = $db->createCommand($sql)->queryOne();
        $this->assertEquals(1, $row['id']);
        $this->assertEquals(1, $row['category_id']);

        $sql = 'SELECT * FROM yii2_test_item_index ORDER BY id ASC';
        $command = $db->createCommand($sql);
        $command->prepare();
        $row = $command->queryOne();
        $this->assertEquals(1, $row['id']);
        $this->assertEquals(1, $row['category_id']);

        $sql = 'SELECT * FROM yii2_test_item_index WHERE id=10';
        $command = $db->createCommand($sql);
        $this->assertFalse($command->queryOne());

        // queryColumn
        $sql = 'SELECT * FROM yii2_test_item_index';
        $column = $db->createCommand($sql)->queryColumn();
        $this->assertEquals(range(1, 2), $column);

        $command = $db->createCommand('SELECT id FROM yii2_test_item_index WHERE id=10');
        $this->assertEquals([], $command->queryColumn());

        // queryScalar
        $sql = 'SELECT * FROM yii2_test_item_index ORDER BY id ASC';
        $this->assertEquals($db->createCommand($sql)->queryScalar(), 1);

        $sql = 'SELECT id FROM yii2_test_item_index ORDER BY id ASC';
        $command = $db->createCommand($sql);
        $command->prepare();
        $this->assertEquals(1, $command->queryScalar());

        $command = $db->createCommand('SELECT id FROM yii2_test_item_index WHERE id=10');
        $this->assertFalse($command->queryScalar());

        $command = $db->createCommand('bad SQL');
        $this->setExpectedException('\yii\db\Exception');
        $command->query();
    }

    /**
     * @depends testQuery
     */
    public function testInsert()
    {
        $db = $this->getConnection();

        $command = $db->createCommand()->insert('yii2_test_rt_index', [
            'title' => 'Test title',
            'content' => 'Test content',
            'type_id' => 2,
            'category' => [1, 2],
            'id' => 1,
        ]);
        $this->assertEquals(1, $command->execute(), 'Unable to execute insert!');

        $rows = $db->createCommand('SELECT * FROM yii2_test_rt_index')->queryAll();
        $this->assertEquals(1, count($rows), 'No row inserted!');
    }

    /**
     * @depends testInsert
     */
    public function testBatchInsert()
    {
        $db = $this->getConnection();

        $command = $db->createCommand()->batchInsert(
            'yii2_test_rt_index',
            [
                'title',
                'content',
                'type_id',
                'category',
                'id',
            ],
            [
                [
                    'Test title 1',
                    'Test content 1',
                    1,
                    [1, 2],
                    1,
                ],
                [
                    'Test title 2',
                    'Test content 2',
                    2,
                    [3, 4],
                    2,
                ],
            ]
        );
        $this->assertEquals(2, $command->execute(), 'Unable to execute batch insert!');

        $rows = $db->createCommand('SELECT * FROM yii2_test_rt_index')->queryAll();
        $this->assertEquals(2, count($rows), 'No rows inserted!');
    }

    /**
     * @depends testInsert
     */
    public function testReplace()
    {
        $db = $this->getConnection();

        $command = $db->createCommand()->replace('yii2_test_rt_index', [
            'title' => 'Test title',
            'content' => 'Test content',
            'type_id' => 2,
            'category' => [1, 2],
            'id' => 1,
        ]);
        $this->assertEquals(1, $command->execute(), 'Unable to execute replace!');

        $rows = $db->createCommand('SELECT * FROM yii2_test_rt_index')->queryAll();
        $this->assertEquals(1, count($rows), 'No row inserted!');

        $newTypeId = 5;
        $command = $db->createCommand()->replace('yii2_test_rt_index', [
            'type_id' => $newTypeId,
            'category' => [3, 4],
            'id' => 1,
        ]);
        $this->assertEquals(1, $command->execute(), 'Unable to update via replace!');

        list($row) = $db->createCommand('SELECT * FROM yii2_test_rt_index')->queryAll();
        $this->assertEquals($newTypeId, $row['type_id'], 'Unable to update attribute value!');
    }

    /**
     * @depends testReplace
     */
    public function testBatchReplace()
    {
        $db = $this->getConnection();

        $command = $db->createCommand()->batchReplace(
            'yii2_test_rt_index',
            [
                'title',
                'content',
                'type_id',
                'category',
                'id',
            ],
            [
                [
                    'Test title 1',
                    'Test content 1',
                    1,
                    [1, 2],
                    1,
                ],
                [
                    'Test title 2',
                    'Test content 2',
                    2,
                    [3, 4],
                    2,
                ],
            ]
        );
        $this->assertEquals(2, $command->execute(), 'Unable to execute batch replace!');

        $rows = $db->createCommand('SELECT * FROM yii2_test_rt_index')->queryAll();
        $this->assertEquals(2, count($rows), 'No rows inserted!');

        $newTypeId = 5;
        $command = $db->createCommand()->replace('yii2_test_rt_index', [
            'type_id' => $newTypeId,
            'id' => 1,
        ]);
        $this->assertEquals(1, $command->execute(), 'Unable to update via replace!');
        list($row) = $db->createCommand('SELECT * FROM yii2_test_rt_index')->queryAll();
        $this->assertEquals($newTypeId, $row['type_id'], 'Unable to update attribute value!');
    }

    /**
     * @depends testInsert
     */
    public function testUpdate()
    {
        $db = $this->getConnection();

        $db->createCommand()->insert('yii2_test_rt_index', [
            'title' => 'Test title',
            'content' => 'Test content',
            'type_id' => 2,
            'id' => 1,
        ])->execute();

        $newTypeId = 5;
        $command = $db->createCommand()->update(
            'yii2_test_rt_index',
            [
                'type_id' => $newTypeId,
                'category' => [3, 4],
            ],
            'id = 1'
        );
        $this->assertEquals(1, $command->execute(), 'Unable to execute update!');

        list($row) = $db->createCommand('SELECT * FROM yii2_test_rt_index')->queryAll();
        $this->assertEquals($newTypeId, $row['type_id'], 'Unable to update attribute value!');
    }

    /**
     * @depends testUpdate
     */
    public function testUpdateWithOptions()
    {
        $db = $this->getConnection();

        $db->createCommand()->insert('yii2_test_rt_index', [
            'title' => 'Test title',
            'content' => 'Test content',
            'type_id' => 2,
            'id' => 1,
        ])->execute();

        $newTypeId = 5;
        $command = $db->createCommand()->update(
            'yii2_test_rt_index',
            [
                'type_id' => $newTypeId,
                'non_existing_attribute' => 10,
            ],
            'id = 1',
            [],
            [
                'ignore_nonexistent_columns' => 1
            ]
        );
        $this->assertEquals(1, $command->execute(), 'Unable to execute update!');
    }

    /**
     * @depends testInsert
     */
    public function testDelete()
    {
        $db = $this->getConnection();

        $db->createCommand()->insert('yii2_test_rt_index', [
            'title' => 'Test title',
            'content' => 'Test content',
            'type_id' => 2,
            'id' => 1,
        ])->execute();

        $command = $db->createCommand()->delete('yii2_test_rt_index', 'id = 1');
        $this->assertEquals(1, $command->execute(), 'Unable to execute delete!');

        $rows = $db->createCommand('SELECT * FROM yii2_test_rt_index')->queryAll();
        $this->assertEquals(0, count($rows), 'Unable to delete record!');
    }

    /**
     * @depends testQuery
     */
    public function testCallSnippets()
    {
        $db = $this->getConnection();

        $query = 'pencil';
        $source = 'Some data sentence about ' . $query;

        $rows = $db->createCommand()->callSnippets('yii2_test_item_index', $source, $query)->queryColumn();
        $this->assertNotEmpty($rows, 'Unable to call snippets!');
        $this->assertContains('<b>' . $query . '</b>', $rows[0], 'Query not present in the snippet!');

        $rows = $db->createCommand()->callSnippets('yii2_test_item_index', [$source], $query)->queryColumn();
        $this->assertNotEmpty($rows, 'Unable to call snippets for array source!');

        $options = [
            'before_match' => '[',
            'after_match' => ']',
            'limit' => 20,
        ];
        $snippet = $db->createCommand()->callSnippets('yii2_test_item_index', $source, $query, $options)->queryScalar();
        $this->assertContains($options['before_match'] . $query . $options['after_match'], $snippet, 'Unable to apply options!');
    }

    /**
     * @depends testQuery
     */
    public function testCallKeywords()
    {
        $db = $this->getConnection();

        $text = 'table pencil';
        $rows = $db->createCommand()->callKeywords('yii2_test_item_index', $text)->queryAll();
        $this->assertNotEmpty($rows, 'Unable to call keywords!');
        $this->assertArrayHasKey('tokenized', $rows[0], 'No tokenized keyword!');
        $this->assertArrayHasKey('normalized', $rows[0], 'No normalized keyword!');

        $text = 'table pencil';
        $rows = $db->createCommand()->callKeywords('yii2_test_item_index', $text, true)->queryAll();
        $this->assertNotEmpty($rows, 'Unable to call keywords with statistic!');
        $this->assertArrayHasKey('docs', $rows[0], 'No docs!');
        $this->assertArrayHasKey('hits', $rows[0], 'No hits!');
    }
}