<?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\Platform\PlatformAbstraction\DatabaseInterface;

class BookingAttributeTable extends Table {
	public const BOOKING_ATTRIBUTE_TABLE = 'booking_attribute';

	public const ID_COLUMN = 'id';
	public const BOOKING_ID_COLUMN = 'booking_id';
	public const ATTRIBUTE_ID_COLUMN = 'attribute_id';
	public const VALUE_COLUMN = 'value';

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

		$columns[self::BOOKING_ID_COLUMN] =implode(" ", [
			$columnTypeMap->UUID(),
			$columnTypeMap->NOT_NULL()
		]);
		$columns[self::ID_COLUMN] = implode(" ", [
			$columnTypeMap->ID(),
			$columnTypeMap->NOT_NULL()
		]);
		$columns[self::ATTRIBUTE_ID_COLUMN] = implode(" ", [
			$columnTypeMap->CODE(),
			$columnTypeMap->NOT_NULL()
		]);

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

		$columns[self::ID_COLUMN] .= ' ' . $columnTypeMap->AUTO_INCREMENT() . ' ' . $columnTypeMap->PRIMARY_KEY();

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

	/**
	 * @param string $bookingId
	 * @param int $attributeId
	 * @param string|string[] $value
	 * @param int|null $id
	 *
	 * @return int id of created booking attribute if new, otherwise id of existing
	 */
	public function set(string $bookingId, int $attributeId, string|array $value, ?int $id = null):int {
		if (!is_array($value)) $value = [$value];

		$table = $this->getSqlTable();
		$array = $this->valuesToArray($bookingId, $attributeId, $value);

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

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

			return $id;
		}

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

		return $this->querySender->getLastGeneratedInsertId();
	}

	public function remove(int $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 removeByBookingId(string $bookingId):void {
		$table = $this->getSqlTable();
		$where = $this->sql->compare( $table->getColumn( self::BOOKING_ID_COLUMN ), $bookingId, true );
		$query = $this->sql->delete( $table, $where );

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

	public function get(int $id): ?array {
		$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 Attribute found with id $id", $result);
			return null;
		}

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

	public function getByBookingId(string $bookingId): array {
		$table = $this->getSqlTable();
		$where = $this->sql->compare( $table->getColumn( self::BOOKING_ID_COLUMN ), $bookingId, true );
		$query = $this->sql->query( $table, $table );
		$query->setWhere( $where );

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

			return [];
		}

		foreach ( $result as $index => $item ) {
			$result[ $index ] = $this->resultArrayToOutputArray( $item );
		}

		return $result;
	}

	/**
	 * @param string $bookingId
	 * @param int $attributeId
	 * @param string[] $value
	 *
	 * @return array
	 */
	public function valuesToArray(string $bookingId, int $attributeId, array $value): array {
		$returnArray = [];

		$returnArray[ self::BOOKING_ID_COLUMN ] = $bookingId;
		$returnArray[ self::ATTRIBUTE_ID_COLUMN ] = $attributeId;

		foreach ($value as $index => $item){
			$value[$index] = str_replace("'", "\'", $item);
		}
		$returnArray[self::VALUE_COLUMN] = implode("','", $value);

		return $returnArray;
	}

	public function resultArrayToOutputArray(array $array): array {
		$array[self::VALUE_COLUMN] = explode("','", $array[self::VALUE_COLUMN]);

		foreach ($array[self::VALUE_COLUMN] as $index => $item){
			$array[self::VALUE_COLUMN][$index] = str_replace("\'", "'", $item);
		}

		if (count($array[self::VALUE_COLUMN]) == 1) $array[self::VALUE_COLUMN] = $array[self::VALUE_COLUMN][0];

		return $array;
	}
}