<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\DocStoreBundle\GenericDoc;

use Doctrine\DBAL\Types\Types;

class FetchQuery implements FetchQueryInterface
{
    /**
     * @var list<string>
     */
    private array $joins = [];

    /**
     * @var list<list<mixed>>
     */
    private array $joinParams = [];

    /**
     * @var array<list<Types::*>>
     */
    private array $joinTypes = [];

    /**
     * @var array<string>
     */
    private array $wheres = [];

    /**
     * @var array<list<mixed>>
     */
    private array $whereParams = [];

    /**
     * @var array<list<Types::*>>
     */
    private array $whereTypes = [];

    public function __construct(
        private readonly string $selectKeyString,
        private readonly string $selectIdentifierJsonB,
        private readonly string $selectDate,
        private string $from = '',
        private array $selectIdentifierParams = [],
        private array $selectIdentifierTypes = [],
        private array $selectDateParams = [],
        private array $selectDateTypes = [],
    ) {}

    public function addJoinClause(string $sql, array $params = [], array $types = []): int
    {
        $this->joins[] = $sql;
        $this->joinParams[] = $params;
        $this->joinTypes[] = $types;

        return count($this->joins) - 1;
    }

    public function addWhereClause(string $sql, array $params = [], array $types = []): int
    {
        $this->wheres[] = $sql;
        $this->whereParams[] = $params;
        $this->whereTypes[] = $types;

        return count($this->wheres) - 1;
    }

    public function removeWhereClause(int $index): void
    {
        if (!array_key_exists($index, $this->wheres)) {
            throw new \UnexpectedValueException('this index does not exists');
        }

        unset($this->wheres[$index], $this->whereParams[$index], $this->whereTypes[$index]);
    }

    public function removeJoinClause(int $index): void
    {
        if (!array_key_exists($index, $this->joins)) {
            throw new \UnexpectedValueException('this index does not exists');
        }

        unset($this->joins[$index], $this->joinParams[$index], $this->joinTypes[$index]);
    }

    public function getSelectKeyString(): string
    {
        return $this->selectKeyString;
    }

    public function getSelectIdentifierJsonB(): string
    {
        return $this->selectIdentifierJsonB;
    }

    public function getSelectIdentifierParams(): array
    {
        return $this->selectIdentifierParams;
    }

    public function getSelectIdentifiersTypes(): array
    {
        return $this->selectIdentifierTypes;
    }

    public function getSelectDate(): string
    {
        return $this->selectDate;
    }

    public function getSelectDateTypes(): array
    {
        return $this->selectDateTypes;
    }

    public function getSelectDateParams(): array
    {
        return $this->selectDateParams;
    }

    public function getFromQuery(): string
    {
        return $this->from.' '.implode(' ', $this->joins);
    }

    public function getFromQueryParams(): array
    {
        $result = [];

        foreach ($this->joinParams as $params) {
            $result = [...$result, ...$params];
        }

        return $result;
    }

    public function getFromQueryTypes(): array
    {
        $result = [];

        foreach ($this->joinTypes as $types) {
            $result = [...$result, ...$types];
        }

        return $result;
    }

    public function getWhereQuery(): string
    {
        return implode(' AND ', $this->wheres);
    }

    public function getWhereQueryParams(): array
    {
        $result = [];

        foreach ($this->whereParams as $params) {
            $result = [...$result, ...$params];
        }

        return $result;
    }

    public function getWhereQueryTypes(): array
    {
        $result = [];

        foreach ($this->whereTypes as $types) {
            $result = [...$result, ...$types];
        }

        return $result;
    }

    public function setSelectIdentifierParams(array $selectIdentifierParams): self
    {
        $this->selectIdentifierParams = $selectIdentifierParams;

        return $this;
    }

    public function setSelectDateParams(array $selectDateParams): self
    {
        $this->selectDateParams = $selectDateParams;

        return $this;
    }

    public function setFrom(string $from): self
    {
        $this->from = $from;

        return $this;
    }

    public function setSelectIdentifierTypes(array $selectIdentifierTypes): self
    {
        $this->selectIdentifierTypes = $selectIdentifierTypes;

        return $this;
    }

    public function setSelectDateTypes(array $selectDateTypes): self
    {
        $this->selectDateTypes = $selectDateTypes;

        return $this;
    }
}
