<?php

/**
 * Фасад для роботи з QueryBuilder
 *
 * @package Flowaxy\Support\Facades
 * @version 1.0.0 Alpha prerelease
 */

declare(strict_types=1);

namespace Flowaxy\Support\Facades;

use Flowaxy\Infrastructure\Persistence\Database\QueryBuilder as QueryBuilderInstance;
use Flowaxy\Infrastructure\Persistence\Database\Database as DatabaseInstance;

final class QueryBuilder extends Facade
{
    protected static function getFacadeAccessor(): string
    {
        return QueryBuilderInstance::class;
    }

    /**
     * Отримати екземпляр Database через фасад
     *
     * @return DatabaseInstance
     */
    private static function database(): DatabaseInstance
    {
        return Database::getFacadeRoot();
    }

    /**
     * Почати запит з таблиці
     *
     * @param string $table
     * @return QueryBuilderInstance
     */
    public static function table(string $table): QueryBuilderInstance
    {
        return new QueryBuilderInstance(static::database());
    }

    /**
     * Вибірка колонок
     *
     * @param string|array<int, string> $columns
     * @return QueryBuilderInstance
     */
    public static function select(string|array $columns = '*'): QueryBuilderInstance
    {
        $query = new QueryBuilderInstance(static::database());

        return $query->select($columns);
    }

    /**
     * Додати умову WHERE
     *
     * @param QueryBuilderInstance $query
     * @param string $column
     * @param string|null $operator
     * @param mixed $value
     * @return QueryBuilderInstance
     */
    public static function where(QueryBuilderInstance $query, string $column, ?string $operator = null, mixed $value = null): QueryBuilderInstance
    {
        return $query->where($column, $operator, $value);
    }

    /**
     * Додати умову WHERE IN
     *
     * @param QueryBuilderInstance $query
     * @param string $column
     * @param array<int, mixed> $values
     * @return QueryBuilderInstance
     */
    public static function whereIn(QueryBuilderInstance $query, string $column, array $values): QueryBuilderInstance
    {
        return $query->whereIn($column, $values);
    }

    /**
     * Додати умову WHERE NOT IN
     *
     * @param QueryBuilderInstance $query
     * @param string $column
     * @param array<int, mixed> $values
     * @return QueryBuilderInstance
     */
    public static function whereNotIn(QueryBuilderInstance $query, string $column, array $values): QueryBuilderInstance
    {
        return $query->whereNotIn($column, $values);
    }

    /**
     * Додати умову OR WHERE
     *
     * @param QueryBuilderInstance $query
     * @param string $column
     * @param string|null $operator
     * @param mixed $value
     * @return QueryBuilderInstance
     */
    public static function orWhere(QueryBuilderInstance $query, string $column, ?string $operator = null, mixed $value = null): QueryBuilderInstance
    {
        return $query->orWhere($column, $operator, $value);
    }

    /**
     * Додати JOIN
     *
     * @param QueryBuilderInstance $query
     * @param string $table
     * @param string $first
     * @param string $operator
     * @param string $second
     * @param string $type
     * @return QueryBuilderInstance
     */
    public static function join(QueryBuilderInstance $query, string $table, string $first, string $operator, string $second, string $type = 'INNER'): QueryBuilderInstance
    {
        return $query->join($table, $first, $operator, $second, $type);
    }

    /**
     * Додати сортування
     *
     * @param QueryBuilderInstance $query
     * @param string $column
     * @param string $direction
     * @return QueryBuilderInstance
     */
    public static function orderBy(QueryBuilderInstance $query, string $column, string $direction = 'ASC'): QueryBuilderInstance
    {
        return $query->orderBy($column, $direction);
    }

    /**
     * Додати групування
     *
     * @param QueryBuilderInstance $query
     * @param string|array<int, string> $columns
     * @return QueryBuilderInstance
     */
    public static function groupBy(QueryBuilderInstance $query, string|array $columns): QueryBuilderInstance
    {
        return $query->groupBy($columns);
    }

    /**
     * Додати умову HAVING
     *
     * @param QueryBuilderInstance $query
     * @param string $column
     * @param string|null $operator
     * @param mixed $value
     * @return QueryBuilderInstance
     */
    public static function having(QueryBuilderInstance $query, string $column, ?string $operator = null, mixed $value = null): QueryBuilderInstance
    {
        return $query->having($column, $operator, $value);
    }

    /**
     * Обмежити кількість результатів
     *
     * @param QueryBuilderInstance $query
     * @param int $limit
     * @return QueryBuilderInstance
     */
    public static function limit(QueryBuilderInstance $query, int $limit): QueryBuilderInstance
    {
        return $query->limit($limit);
    }

    /**
     * Встановити зміщення
     *
     * @param QueryBuilderInstance $query
     * @param int $offset
     * @return QueryBuilderInstance
     */
    public static function offset(QueryBuilderInstance $query, int $offset): QueryBuilderInstance
    {
        return $query->offset($offset);
    }

    /**
     * Отримати всі записи
     *
     * @param QueryBuilderInstance $query
     * @return array<int, array<string, mixed>>
     */
    public static function get(QueryBuilderInstance $query): array
    {
        return $query->get();
    }

    /**
     * Отримати перший запис
     *
     * @param QueryBuilderInstance $query
     * @return array<string, mixed>|false
     */
    public static function first(QueryBuilderInstance $query): array|false
    {
        return $query->first();
    }

    /**
     * Підрахувати кількість записів
     *
     * @param QueryBuilderInstance $query
     * @return int
     */
    public static function count(QueryBuilderInstance $query): int
    {
        $results = $query->get();
        return count($results);
    }

    /**
     * Перевірити існування записів
     *
     * @param QueryBuilderInstance $query
     * @return bool
     */
    public static function exists(QueryBuilderInstance $query): bool
    {
        $result = $query->first();
        return $result !== false;
    }
}
