<?php

namespace Opentalent\OtCore\Tests\Unit;

use Doctrine\DBAL\Driver\Statement;
use Prophecy\Argument;
use Prophecy\Prophet;
use TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Core\Database\Query\Restriction\QueryRestrictionContainerInterface;

/**
 * A special prophet designed for mocking QueryBuilder objects
 *
 * Class QueryBuilderProphet
 */
class QueryBuilderProphet extends Prophet
{
    /**
     * @var array
     */
    private $willReturn;

    public function __construct(
        ...$willReturn
    ) {
        parent::__construct();
        $this->setWillReturn(...$willReturn);
    }

    public function setWillReturn(...$willReturn) {
        if (!is_array($willReturn) ) {
            $willReturn = [$willReturn];
        }
        $this->willReturn = [];
        $this->addToWillReturn(...$willReturn);
    }

    public function addToWillReturn(...$willReturn) {
        foreach ($willReturn as $row) {
            $this->willReturn[] = $row;
        }
    }

    public function prophesize($classOrInterface = null)
    {
        if ($classOrInterface != null) {
            throw new \InvalidArgumentException('QueryBuilderProphet::prophesize does not accept any argument');
        }

        // Prophesize
        $queryBuilder = parent::prophesize(QueryBuilder::class);
        $statement = parent::prophesize(Statement::class);
        $queryRestrictions = parent::prophesize(QueryRestrictionContainerInterface::class);
        $expressionBuilder = parent::prophesize(ExpressionBuilder::class);

        // Mock restrictions
        $queryBuilder->getRestrictions()->willReturn($queryRestrictions);
        $queryRestrictions->removeAll()->willReturn($queryRestrictions);

        // Mock expression builder
        $expressionBuilder->eq(Argument::any(), Argument::any())->willReturn("");
        $queryBuilder->expr()->willReturn($expressionBuilder);

        // Mock Querybuilder
        $queryBuilder->select(Argument::cetera())->willReturn($queryBuilder);
        $queryBuilder->from(Argument::cetera())->willReturn($queryBuilder);
        $queryBuilder->innerJoin(Argument::cetera())->willReturn($queryBuilder);
        $queryBuilder->where(Argument::any())->willReturn($queryBuilder);
        $queryBuilder->andWhere(Argument::any())->willReturn($queryBuilder);

        // Mock Statements
        $statement->fetchAll()->willReturn(...$this->willReturn);
        $statement->fetch()->willReturn($this->willReturn[0]);
        $statement->fetchColumn(0)->willReturn($this->willReturn[0]);

        // Mock execution
        $queryBuilder->execute()->willReturn($statement);

        return $queryBuilder;
    }
}
