<?php

namespace Planaday\Database\MySQL\QueryBuilding;

use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLColumn;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLQuery;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLUseInterfaces\SQLCondition;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLUseInterfaces\SQLFromable;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLUseInterfaces\SQLSelectable;

class MySQLQuery implements SQLQuery {
	/** @var SQLSelectable[] */
	protected array $select;
	protected bool $isDistinct = false;
	protected SQLCondition $where;
	protected SQLCondition $having;
	/** @var SQLColumn[] */
	protected array $groupBy = [];
	/** @var SQLColumn[] */
	protected array $orderBy = [];
	protected int $limit;
	protected int $offset;

	public function __construct(
		protected SQLFromable $from,
		SQLSelectable $select
	) {
		$this->select = [$select];
	}

	public function isDistinct(): void {
		$this->isDistinct = true;
	}

	public function setLimit(int $limit ): void {
		$this->limit = $limit;
	}

	public function setOffset(int $offset ): void {
		$this->offset = $offset;
	}

	public function setFrom( SQLFromable $from ): void {
		$this->from = $from;
	}

	public function getFrom(): SQLFromable {
		return $this->from;
	}

	public function addSelect(SQLSelectable $select ): void {
		$this->select[] = $select;
	}

	public function setWhere(SQLCondition $where ): void {
		$this->where = $where;
	}

	public function setGroupBy(SQLColumn $groupBy ): void {
		$this->groupBy[] = $groupBy;
	}

	public function setOrderBy(SQLColumn $orderBy ): void {
		$this->orderBy[] = $orderBy;
	}

	public function setHaving(SQLCondition $having ): void {
		$this->having = $having;
	}

	public function toQuery():string {
		$selectQueries = [];
		$groupByQueries = [];
		$orderByQueries = [];

		foreach ($this->select as $select){
			$selectQueries[] = $select->toSelectQuery();
		}
		foreach ($this->groupBy as $groupBy){
			$groupByQueries[] = $groupBy->getFullColumnIdentifier();
		}
		foreach ($this->orderBy as $orderBy){
			$orderByQueries[] = $orderBy->getOrderQuery();
		}

		$query = 'SELECT ' . ($this->isDistinct ? 'DISTINCT ' : '') . implode(', ', $selectQueries);
		$query .= ' FROM ' . $this->from->getFromQuery();
		if( isset($this->where) ) $query .= ' WHERE ' . $this->where->toConditionQuery();
		if(count($groupByQueries) > 0) $query .= ' GROUP BY ' . implode(', ', $groupByQueries);
		if( isset($this->having) ) $query .= ' HAVING ' . $this->having->toConditionQuery();
		if(count($orderByQueries) > 0) $query .= ' ORDER BY ' . implode(', ', $orderByQueries);
		if (isset($this->limit)) $query .= ' LIMIT ' . $this->limit;
		if (isset($this->offset)) $query .= ' OFFSET ' . $this->offset;

		return $query;
	}
}