<?php

namespace Planaday\Database\SQLDatabaseControllers;

use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLColumn;
use Planaday\Database\Abstraction\SQLQuery\QueryBuilding\SQLTable;
use Planaday\Database\Abstraction\SQLQuery\SQLFactory;
use Planaday\Platform\PlatformAbstraction\DatabaseInterface;
use Planaday\Utility\Debug\Log\Logging;

class Table {
	use Logging;

	protected bool $isTableCreatedProperly = false;

	/**
	 * @param DatabaseInterface $querySender
	 * @param SQLFactory $sql
	 * @param string $name
	 * @param array<string, string> $columns
	 * @param array<string, string> $constraints
	 */
	public function __construct(
		protected DatabaseInterface $querySender,
		protected SQLFactory $sql,
		protected string $name,
		protected array $columns,
		protected array $constraints
	) {
		$this->initializeTable();
	}

	public function getName(): string {
		return $this->name;
	}

	/**
	 * @return string[]
	 */
	public function getColumns(): array {
		return $this->columns;
	}

	/**
	 * @return string[]
	 */
	public function getConstraints(): array {
		return $this->constraints;
	}

	public function initializeTable(): void{
		if ($this->isTableValid()) {
			$this->logInfo("table $this->name is complete");
			$this->isTableCreatedProperly = true;
			return;
		}

		$this->logWarning("Table $this->name is invalid, (re)building table");

		//drop table if it exists
		$this->querySender->sendQuery($this->getDropTableQuery());

		//create table
		$this->querySender->sendQuery($this->getCreateTableQuery());

		if (!$this->isTableValid()) {
			$this->logError("table $this->name cannot be created or fixed", ['columns' => $this->querySender->getColumnsTable($this)]);
			$this->isTableCreatedProperly = false;
		}
	}

	public function rebuildTable(): void {
		$this->querySender->sendQuery($this->getDropTableQuery());
		$this->querySender->sendQuery($this->getCreateTableQuery());
	}

	public function getCreateTableQuery(): string {
		$sql = "CREATE TABLE IF NOT EXISTS " . $this->querySender->convertTableString($this->name) . " (";

		foreach ($this->getColumns() as $column => $dataType){
			$sql .= "$column $dataType, ";
		}

		foreach ($this->getConstraints() as $constraintName => $constraint){
			$sql .= "CONSTRAINT $constraintName $constraint, ";
		}

		$sql = substr($sql, 0, -2);

		$sql .= ");";

		return $sql;
	}

	public function getDropTableQuery(): string {
		return "DROP TABLE IF EXISTS " . $this->querySender->convertTableString($this->name) . ";";
	}

	public function isTableValid(): bool {
		$columns = $this->querySender->getColumnsTable($this);
		$expectedColumns = array_keys($this->getColumns());

		if (count($columns) != count($expectedColumns)) {
			$this->isTableCreatedProperly = false;
			return false;
		}

		foreach ($expectedColumns as $column){
			if (!array_key_exists($column, $columns)){
				$this->isTableCreatedProperly = false;
				return false;
			}
		}

		$this->isTableCreatedProperly = true;
		return true;
	}

	public function getSqlTable(): SQLTable {
		return $this->sql->table($this->querySender->convertTableString($this->name));
	}

	public function getSqlColumn(string $columnName): SQLColumn {
		return $this->getSqlTable()->getColumn($columnName);
	}

	public function isTableCreatedProperly(): bool {
		return $this->isTableCreatedProperly;
	}
}