<?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\Address;
use Planaday\Entities\Booking\DTO\BookingCompany;
use Planaday\Entities\Booking\DTO\BookingInvoice;
use Planaday\Platform\PlatformAbstraction\DatabaseInterface;

class BookingCompanyTable extends Table {
	public const BOOKING_COMPANY_TABLE = 'booking_company';

	public const ID_COLUMN = 'id';
	public const NAME_COLUMN = 'name';
	public const ADDRESS_COLUMN = 'address_id';
	public const EMAIL_COLUMN = 'email';
	public const PHONE_NUMBER_COLUMN = 'phone_number';
	public const INVOICE_EMAIL_COLUMN = 'invoice_email';
	public const INVOICE_ADDRESS_COLUMN = 'invoice_address';

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

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

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

		$columns[self::ADDRESS_COLUMN] =
		$columns[self::INVOICE_ADDRESS_COLUMN] = implode(" ", [
			$columnTypeMap->ID(),
			$columnTypeMap->DEFAULT_NULL()
		]);

		$columns[self::EMAIL_COLUMN] =
		$columns[self::INVOICE_EMAIL_COLUMN] = implode(" ", [
			$columnTypeMap->EMAIL(),
			$columnTypeMap->DEFAULT_NULL()
		]);

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

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

	/**
	 * @param BookingCompany $company
	 * @param int|null $address
	 * @param int|null $financialAddress
	 *
	 * @return int id of created company if new, otherwise id of existing
	 */
	public function set(BookingCompany $company, ?int $address, ?int $financialAddress):int {
		$table = $this->getSqlTable();
		$array = $this->companyObjectToArray($company, $address, $financialAddress);

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

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

			return $company->getDatabaseId();
		}

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

		$company->setDatabaseId($this->querySender->getLastGeneratedInsertId());
		return $company->getDatabaseId();
	}

	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() );
	}

	/**
	 * @param int $id
	 * @param callable(int):(null|Address) $getAddressCallback
	 *
	 * @return BookingCompany|null
	 */
	public function get(int $id, callable $getAddressCallback): ?BookingCompany {
		$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 company found with id $id", $result);
			return null;
		}

		return $this->companyArrayToObject($result[0], $getAddressCallback);
	}

	public function companyObjectToArray(BookingCompany $company, ?int $addressId, ?int $financialAddress): array {
		$returnArray = [];

		$returnArray[ self::NAME_COLUMN ] = $company->getName();
		$returnArray[ self::ADDRESS_COLUMN ] = $addressId;
		$returnArray[ self::EMAIL_COLUMN ] = $company->getEmail();
		$returnArray[ self::PHONE_NUMBER_COLUMN ] = $company->getPhoneNumber();
		$returnArray[ self::INVOICE_ADDRESS_COLUMN ] = $financialAddress;
		$invoiceEmail = ($company->getInvoice() !== null && $company->getInvoice()->getEmail() !== null) ? $company->getInvoice()->getEmail() : null;
		$returnArray[ self::INVOICE_EMAIL_COLUMN ] = $invoiceEmail;

		return $returnArray;
	}

	/**
	 * @param array $array
	 * @param callable(int):(null|Address) $getAddressCallback
	 *
	 * @return BookingCompany
	 */
	public function companyArrayToObject(array $array, callable $getAddressCallback): BookingCompany {
		$address = ($array[self::ADDRESS_COLUMN] != null) ? $getAddressCallback( $array[self::ADDRESS_COLUMN] ) : null;
		$address = $address ?? new Address();

		$invoiceAddress = ($array[self::INVOICE_ADDRESS_COLUMN] != null) ? $getAddressCallback( $array[self::INVOICE_ADDRESS_COLUMN] ) : null;
		$invoiceAddress = $invoiceAddress ?? new Address();


		$invoice = (new BookingInvoice())
			->setEmail( $array[ self::INVOICE_EMAIL_COLUMN ] )
			->setAddress($invoiceAddress);

		return (new BookingCompany())
			->setName($array[ self::NAME_COLUMN ])
			->setAddress($address)
			->setEmail($array[ self::EMAIL_COLUMN ])
			->setPhoneNumber($array[ self::PHONE_NUMBER_COLUMN ])
			->setInvoice($invoice)
			->setDatabaseId( $array[ self::ID_COLUMN ] );
	}
}