<?php

namespace Planaday\Database\SQLDatabaseControllers\Booking;

use Planaday\Database\Abstraction\SQLQuery\ColumnTypeMap;
use Planaday\Database\Abstraction\SQLQuery\SQLFactory;
use Planaday\Database\SQLDatabaseControllers\Table;
use Planaday\Entities\Booking\DTO\Transaction;
use Planaday\Entities\Booking\Enum\TransactionStatus;
use Planaday\Platform\PlatformAbstraction\DatabaseInterface;

class TransactionTable extends Table {
	public const TRANSACTION_TABLE = 'transaction';

	public const ID_COLUMN = 'id';
	public const STATUS_COLUMN = 'status';
	public const METHOD_COLUMN = 'method';
	public const DESCRIPTION_COLUMN = 'description';
	public const AMOUNT_COLUMN = 'amount';
	public const LAST_UPDATED_AT_COLUMN = 'last_updated_at';


	public function __construct( DatabaseInterface $querySender, SQLFactory $sql, ColumnTypeMap $columnTypeMap ) {
		$columns = [];

		$columns[self::ID_COLUMN] = implode(" ", [
			$columnTypeMap->CODE(),
			$columnTypeMap->NOT_NULL(),
			$columnTypeMap->PRIMARY_KEY()
		]);

		$columns[self::STATUS_COLUMN] = implode(" ", [
			$columnTypeMap->STATUS(),
			$columnTypeMap->NOT_NULL()
		]);

		$columns[self::METHOD_COLUMN] = implode(" ", [
			$columnTypeMap->CODE(),
			$columnTypeMap->DEFAULT_NULL()
		]);

		$columns[self::AMOUNT_COLUMN] = implode(" ", [
			$columnTypeMap->PRICE(),
			$columnTypeMap->DEFAULT_NULL()
		]);

		$columns[self::LAST_UPDATED_AT_COLUMN] = $columnTypeMap->LAST_UPDATED_TIMESTAMP();

		parent::__construct( $querySender, $sql, self::TRANSACTION_TABLE, $columns, [] );
	}

	public function set(Transaction $transaction): void{
		$table = $this->getSqlTable();
		$array = $this->transactionObjectToArray($transaction);

		if ($this->querySender->idExists($this, $transaction->getId())) {
			$where = $this->sql->compare($table->getColumn(self::ID_COLUMN), $transaction->getId(), true);
			$query = $this->sql->update($table, $where, $array);

			$this->querySender->sendQuery($query->toQuery());
			return;
		}

		$query = $this->sql->insert($table, $array);
		$this->querySender->sendQuery($query->toQuery());
	}

	public function remove(string $id):void {
		$table = $this->getSqlTable();
		$where = $this->sql->compare( $table->getColumn( self::ID_COLUMN ), $id, true );
		$query = $this->sql->delete( $table, $where );

		$this->querySender->sendQuery( $query->toQuery() );
	}

	public function get(string $id): ?Transaction {
		$table = $this->getSqlTable();
		$where = $this->sql->compare($table->getColumn(self::ID_COLUMN), $id, true);
		$query = $this->sql->query($table, $table);
		$query->setWhere($where);
		$query->setLimit(1);

		$result = $this->querySender->sendQuery($query->toQuery());
		if (!is_array($result) || count($result) < 1) {
			$this->logWarning("No transaction found with id $id", $result);
			return null;
		}

		return $this->transactionArrayToObject($result[0]);
	}

	public function transactionObjectToArray(Transaction $transaction): array {
		$returnArray = [];

		$returnArray[ self::AMOUNT_COLUMN ] = $transaction->getTotalCost();
		$returnArray[ self::ID_COLUMN ] = $transaction->getId();
		$returnArray[ self::METHOD_COLUMN ] = $transaction->getMethod();
		$returnArray[ self::STATUS_COLUMN ] = $transaction->getStatus()->value;

		return $returnArray;
	}

	public function transactionArrayToObject(array $array): Transaction {
		return (new Transaction( $array[ self::ID_COLUMN ] ))
			->setTotalCost( $array[ self::AMOUNT_COLUMN ])
			->setMethod( $array[ self::METHOD_COLUMN ])
			->setStatus( TransactionStatus::tryFrom($array[ self::STATUS_COLUMN ]) ?? TransactionStatus::Pending);
	}
}