<?php

namespace Planaday\Database\Abstraction\SQLQuery;

use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLAggregates\SQLAvg;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLAggregates\SQLCount;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLAggregates\SQLMax;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLAggregates\SQLMin;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLAggregates\SQLSum;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLColumn;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLDelete;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLInsert;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLJoin;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLOperators\SQLAnd;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLOperators\SQLBetween;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLOperators\SQLComparison;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLOperators\SQLExists;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLOperators\SQLIn;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLOperators\SQLLike;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLOperators\SQLNot;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLOperators\SQLOr;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLOperators\SQLSubqueryComparisonModifier;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLQuery;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLTable;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLUpdate;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLUseInterfaces\SQLComparable;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLUseInterfaces\SQLCondition;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLUseInterfaces\SQLFromable;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLUseInterfaces\SQLSelectable;

interface SQLFactory {

	public function query(SQLFromable $from, SQLSelectable $select): SQLQuery;

	/**
	 * @param SQLTable $table
	 * @param SQLCondition $where
	 * @param array<string, string|int> $values
	 *
	 * @return SQLUpdate
	 */
	public function update(SQLTable $table, SQLCondition $where, array $values): SQLUpdate;

	/**
	 * @param SQLTable $table
	 * @param mixed[] $values
	 *
	 * @return SQLInsert
	 */
	public function insert(SQLTable $table, array $values): SQLInsert;

	public function delete(SQLTable $table, SQLCondition $where): SQLDelete;

	public function join(SQLFromable $left, SQLTable $right, SQLColumn $leftColumn, SQLColumn $rightColumn, bool $includeAllLeft = false, bool $includeAllRight = false): SQLJoin;

	public function table(string $table, ?string $alias = null): SQLTable;

	public function column(string $columnName, ?string $tableAlias = null): SQLColumn;

	public function and(SQLCondition ...$conditions): SQLAnd;

	public function or(SQLCondition ...$conditions): SQLOr;

	/**
	 * @param SQLComparable $toBeTested the value to be tested
	 * @param string|int $valueMin
	 * @param string|int $valueMax
	 * @param bool $betweenOrOutside if false will use NOT BETWEEN
	 *
	 * @return SQLBetween
	 */
	public function between(SQLComparable $toBeTested, string|int $valueMin, string|int $valueMax, bool $betweenOrOutside = true): SQLBetween;

	/**
	 * @param SQLComparable $toBeTested
	 * @param null|string|int|float|SQLSubqueryComparisonModifier $value
	 * @param bool $isEqual
	 * @param bool|null $isGreater
	 *
	 * @return SQLComparison
	 */
	public function compare(SQLComparable $toBeTested, null|string|int|float|SQLSubqueryComparisonModifier $value, bool $isEqual, ?bool $isGreater = null): SQLComparison;

	public function exists(SQLQuery $subQuery): SQLExists;

	/**
	 * @param SQLComparable $toBeTested the value to be tested
	 * @param array|SQLQuery $values can be an array of values or a subquery
	 * @param bool $inOrOutside if false will use NOT IN
	 *
	 * @return SQLIn
	 */
	public function in(SQLComparable $toBeTested, array|SQLQuery $values, bool $inOrOutside = true): SQLIn;

	public function like(SQLColumn $toBeTested, string $value): SQLLike;

	public function not(SQLCondition $condition): SQLNot;

	public function subquery(SQLQuery $subQuery, bool $needsAll): SQLSubqueryComparisonModifier;

	public function avg(SQLColumn $column, ?string $alias = null): SQLAvg;

	public function sum(SQLColumn $column, ?string $alias = null): SQLSum;

	public function count(SQLColumn $column, ?string $alias = null): SQLCount;

	public function max(SQLColumn $column, ?string $alias = null): SQLMax;

	public function min(SQLColumn $column, ?string $alias = null): SQLMin;
}