<?php

/**
 * Exportní API serveru RealityMix.
 *
 * @category   Dalten
 * @package    Export
 * @subpackage Api
 */
class Dalten_Export_Api_RealityMix implements Dalten_Export_Api_LoggableApiInterface,
	Dalten_Export_Api_ProjectApiInterface, Dalten_Export_Api_TopListingInterface,
	Dalten_Export_Api_ListListingsInterface
{

	/**
	 * Označuje export fotografií nabídky.
	 */
	const EXPORT_LISTING_IMAGES = 'listing';

	/**
	 * Označuje export fotografií projektu.
	 */
	const EXPORT_PROJECT_IMAGES = 'project';

	/**
	 * Konvertor hodnot.
	 *
	 * @var Dalten_Export_RealityMix
	 */
	private $_export;

	/**
	 * Nastavení.
	 *
	 * @var Serenity_Config_Config
	 */
	private $_config;

	/**
	 * Backend.
	 *
	 * @var Dalten_Export_Api_Backend_RealityMix
	 */
	private $_backend;

	/**
	 * Session ID.
	 *
	 * @var string|null
	 */
	private $_sessionId = null;

	/**
	 * Konstruktor.
	 *
	 * @param Dalten_Export_RealityMix             $export  Konvertor hodnot.
	 * @param Serenity_Config_Config               $config  Nastavení.
	 * @param Dalten_Export_Api_Backend_RealityMix $backend Backend.
	 */
	public function __construct(Dalten_Export_RealityMix $export,
		Serenity_Config_Config $config,
		Dalten_Export_Api_Backend_RealityMix $backend)
	{
		$this->_export = $export;
		$this->_config = $config;
		$this->_backend = $backend;
	}

	/**
	 * Naváže spojení se vzdáleným serverem.
	 *
	 * @param string $login            Přihlašovací jméno.
	 * @param string $password         Heslo.
	 * @param string $softwareKey      Softwarový klíč.
	 * @param array  $additionalParams Pole dalších parametrů.
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru.
	 */
	public function openConnection($login, $password, $softwareKey = '', array $additionalParams = array())
	{
		$hash = $this->_backend->getHash($login);
		$password = md5(md5($password) . $hash->output->hashKey);
		$this->_sessionId = $hash->output->sessionId;

		// todo: když se nepovede getHash, zkoušíme se přihlásit jako "Litujeme, ale při zpracování požadavku došlo k chybě. Zkuste to prosím později."
		$response = $this->_backend->login($this->_sessionId, $password, $softwareKey);

		$status = isset($response->status) ? $response->status : 0;
		$statusMessage = isset($response->statusMessage)
			? $response->statusMessage
			: 'Server nevrátil žádnou odpověď';

		return new Dalten_Export_Api_ServerResponse(
			$status == 200,
			$status,
			$statusMessage
		);
	}

	/**
	 * Vyexportuje uživatele.
	 *
	 * @param array $userData Data uživatele ve formátu iRest 1.
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru, jestli se export podařil nebo co selhalo.
	 */
	public function addUser(array $userData)
	{
		$photo = null;
		if (!empty($userData['foto'])) {
			$photo = (string) realpath($userData['foto']);
			if ($photo) {
				$photo = file_get_contents($photo);
			}
		}

		$jmenoCele = $userData['uzivatel_os_jmeno'] . (!empty($userData['uzivatel_os_prostredni_jmeno']) ?  ' ' . $userData['uzivatel_os_prostredni_jmeno'] : '') . ' ' . $userData['uzivatel_os_prijmeni'];

		if (!empty($userData['uzivatel_tituly_pred_jmenem'])) {
			$jmenoCele = $userData['uzivatel_tituly_pred_jmenem'] . ' ' . $jmenoCele;
		}

		if (!empty($userData['uzivatel_tituly_za_jmenem'])) {
			$jmenoCele = $jmenoCele . ' ' . $userData['uzivatel_tituly_za_jmenem'];
		}

		$response = $this->_backend->addSellerData(
			$this->_sessionId,
			$userData['id'],
			array(
				'seller_name' => $jmenoCele,
				'seller_ic' => (int) $userData['makler_ico'],
				'seller_is_employee' => (bool) $userData['makler_je_zamestnanec_na_hpp'],
				'contact_gsm' => $userData['telefon'],
				'contact_email' => $userData['email'],
				'contact_phone' => empty($userData['pevna_linka']) ? '' : $userData['pevna_linka'],
				'seller_note' => $userData['moto'],
				'seller_email' => $userData['sekundarni_email'],
                'seller_data_box' => empty($userData['datova_schranka_id']) ? '' : $userData['datova_schranka_id'],
				'photo' => $photo
			)
		);

		$message = $response->statusMessage;
		if ($message == 'Není vyplněn povinný parametr seller_ic') {
			$message = 'Není vyplněn povinný parametr seller_ic (v profilu makléře vyplňte IČ nebo formu spolupráce HPP)';
		}

		return new Dalten_Export_Api_ServerResponse(
			$response->status == 200,
			$response->status,
			$message,
			array($response->output)
		);
	}

	/**
	 * Vyexportuje nabídku.
	 *
	 * @param array $listingData      Data nabídky ve formátu iRest 1.
	 * @param array $userData         Data uživatele (makléře, kterému nabídka patří) ve formátu iRest 1.
	 * @param array $images           Pole fotografií nabídky ve formátu iRest 1.
	 * @param array $additionalParams Pro tento export, nejsou přídavná data potřebná.
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru, jestli se export podařil nebo co selhalo.
	 */
	public function addListing(
		array $listingData, array $userData, array $images = array(), array $additionalParams = array()
	)
	{
		$type = 'type_' . $listingData['nemovitost_typ'];

		$basicData = $this->_export->convertEntityValues('basic', $listingData, $this->_config->basic);
		$typeData = $this->_export->convertEntityValues($type, $listingData, $this->_config->$type);

		$supportedVideoFormat = true;
		$basicData['video_url'] = '';
		$basicData['virtual_tour'] = '';

		// předáváme odkaz na youtube
		if (!empty($listingData['nemovitost_video_prohlidka'])) {
			if (Dalten_Export_Helper_YoutubeIdExtractor::extractYoutubeId($listingData['nemovitost_video_prohlidka'])) {
				$basicData['video_url'] = $listingData['nemovitost_video_prohlidka'];
			} else {
				$supportedVideoFormat = false; // chybová hláška - nepodporovaný formát videa
			}
		} else if (!empty($listingData['nemovitost_virtualni_prohlidka'])) {
			if (Dalten_Export_Helper_YoutubeIdExtractor::extractYoutubeId($listingData['nemovitost_video_prohlidka'])) {
				$basicData['video_url'] = $listingData['nemovitost_virtualni_prohlidka'];
			} else {
				// tady naopak chybovou hlášku schválně nemáme
			}
		}

		if (isset($listingData['nemovitost_virtualni_prohlidka'])
			&& preg_match('~vp\d+~', $listingData['nemovitost_virtualni_prohlidka'])) {
			$basicData['virtual_tour'] = 'http://www.nview.cz/vp/' . $listingData['nemovitost_virtualni_prohlidka'];
		}

		if (!empty($listingData['nemovitost_virtualni_prohlidka']) && (
				strpos($listingData['nemovitost_virtualni_prohlidka'], 'http://www.nview.cz/vp/')===0 ||
				strpos($listingData['nemovitost_virtualni_prohlidka'], 'https://www.nview.cz/vp/')===0
			)) {
			$basicData['virtual_tour'] = $listingData['nemovitost_virtualni_prohlidka'];
		}

        $matterportUrl = Dalten_Export_Helper_MatterportIdExtractor::normalizeMatterportUrl($listingData['nemovitost_virtualni_prohlidka']);
		if ($matterportUrl) {
			$basicData['virtual_tour'] = $matterportUrl;
		}

		if (!empty($userData)) {
			if (empty($userData['id'])) {
				$userData['id'] = sprintf('%u', crc32(serialize($userData)));
			}

			$response = $this->addUser($userData);
			if (!$response->wasSuccessful()) {
				return $response;
			}

			$basicData['seller_rkid'] = $userData['id'];
		}

		if (isset($additionalParams['listing']['hide_price']) && (boolean) $additionalParams['listing']['hide_price']) {
			$basicData['advert_price'] = 0;
			$priceDescription = 'Info v RK.';
			if (isset($basicData['advert_price_note'])) {
				$description = trim($basicData['advert_price_note']);
				if (!empty($description)) {
					$priceDescription = $description;
				}
			}
			$basicData['advert_price_note'] = $priceDescription;
		}

		$hidePortals = '00';
		if (isset($additionalParams['listing']['hide_portals'])) {
			// data dostáváme v podobě pole integerů, když v něm je integer s danou hodnotou pošleme ho
			// 1=Prima HbbTV
			$hidePortals[1] = in_array(1, $additionalParams['listing']['hide_portals']) ? 1 : 0;
		}
		$basicData['hide_portals'] = $hidePortals;

		if (
			isset($basicData['energy_performance_attachment'])
		) {
			$priloha = realpath($basicData['energy_performance_attachment']);
			//nemáme soubor se štítkem (realpath nechá projít prázdnou hodnotu)
			if (empty($basicData['energy_performance_attachment']) || $priloha===false) {
				unset($basicData['energy_performance_attachment']);
			} else {
				$basicData['energy_performance_attachment'] = file_get_contents($basicData['energy_performance_attachment']);
			}
		}

		$addListingResponse = $this->_backend->addAdvert($this->_sessionId, $basicData, $typeData);
		if ($addListingResponse->status != 200) {
			return new Dalten_Export_Api_ServerResponse(
				false,
				$addListingResponse->status,
				$this->translateErrorMessageParts($addListingResponse->statusMessage),
				$addListingResponse->output
			);
		}

		if (isset($listingData['kod'])) {
			$response = $this->_processImageUpdate($listingData['kod'], $images, self::EXPORT_LISTING_IMAGES, !empty($additionalParams['listing']['reexport_photos']));
			if (!$response->wasSuccessful()) {
				return $response;
			}
		}

		$notices = array();
		if (!empty($addListingResponse->output->userMessages)) {
			foreach ($addListingResponse->output->userMessages as $notice) {
				$notices[] = $notice;
			}
		}
		if (!$supportedVideoFormat) {
			$notices[] = 'Video se nezobrazí, zadaný formát URL videa není podporován. ';
		}

		$response = new Dalten_Export_Api_ServerResponse(true, 200, implode(PHP_EOL, $notices), $addListingResponse->output);
		if (!empty($addListingResponse->output->advert_id)) {
			$response->setData(array('advert_id'=>$addListingResponse->output->advert_id));
		}
		return $response;
	}

	/**
	 * Přeloží části chybové hlášky.
	 *
	 * @param string $statusMessage Hláška k přeložení.
	 *
	 * @return string Přeložená hláška.
	 */
	protected function translateErrorMessageParts($statusMessage)
	{
		return str_replace(
			['plot_area', 'building_area'],
			['Plocha parcely', 'Zastavěná plocha'],
			$statusMessage
		);
	}

	/**
	 * Odstraní nabídku ze vzdáleného serveru.
	 *
	 * @param array $listingData      Data nabídky ve formátu iRest 1.
	 * @param array $additionalParams Specifická data pro daný export (zde prázdné pole).
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru.
	 */
	public function deleteListing(array $listingData, array $additionalParams = array())
	{
		$response = $this->_backend->delAdvert(
			$this->_sessionId,
			null,
			isset($listingData['kod']) ? $listingData['kod'] : null
		);

		return new Dalten_Export_Api_ServerResponse(
			$response->status == 200,
			$response->status,
			$response->statusMessage
		);
	}

	/**
	 * Nastaví logger pro backend.
	 *
	 * Logger bude použit pouze pokud to backend dovoluje.
	 *
	 * @param Dalten_Export_Api_Backend_Logger_LoggerInterface $logger Instance loggeru.
	 *
	 * @return bool Podařilo se přiřadit backendu logger?
	 */
	public function setLogger(Dalten_Export_Api_Backend_Logger_LoggerInterface $logger)
	{
		if ($this->_backend instanceof Dalten_Export_Api_Backend_LoggableBackendInterface) {
			$this->_backend->setLogger($logger);
		}
		return false;
	}

	/**
	 * Odstraní nastavený logger pro backend.
	 *
	 * @return Dalten_Export_Api_LoggableApiInterface Fluent interface.
	 */
	public function removeLogger()
	{
		$this->_backend->removeLogger();
	}

	/**
	 * Vyexportuje projekt.
	 *
	 * @param array $projectData      Data projektu ve formátu iRest 1.
	 * @param array $userData         Data uživatele (makléře, kterému projekt patří) ve formátu iRest 1.
	 * @param array $listingIds       Pole s IDčky nabídek (ve tvaru id=>kod).
	 * @param array $images           Pole fotografií projektu ve formátu iRest 1.
	 * @param array $additionalParams Údaje které vrací server při exportu a jsou potřeba pro další
	 *                                práci s nabídkou.
	 *                                Data můžou sloužit pro editaci apod...
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru, jestli se export podařil nebo co selhalo.
	 */
	public function addProject(array $projectData, array $userData, array $listingIds = array(),
		array $images = array(), array $additionalParams = array())
	{

		if (empty($projectData['developer_nazev'])) {
			return new Dalten_Export_Api_ServerResponse(
				false,
				500,
				'Musí být vyplněny údaje developera projektu.'
			);
		}

		$convertedData = $this->_export->convertEntityValues('project', $projectData, $this->_config->project);

		$addProjectResponse = $this->_backend->addDevel(
			$this->_sessionId,
			$convertedData,
			array(),
			array_values($listingIds)
		);
		if ($addProjectResponse->status != 200) {
			return new Dalten_Export_Api_ServerResponse(
				false,
				$addProjectResponse->status,
				$addProjectResponse->statusMessage,
				$addProjectResponse->output
			);
		}

		if (isset($projectData['kod'])) {
			$response = $this->_processImageUpdate($projectData['kod'], $images, self::EXPORT_PROJECT_IMAGES, !empty($additionalParams['reexport_photos']));
			if (!$response->wasSuccessful()) {
				return $response;
			}
		}

		$response = new Dalten_Export_Api_ServerResponse(true, 200, '', $addProjectResponse->output);
		if (isset($addProjectResponse->output->developer_id)) {
			$response->setData(['detailUrl'=>sprintf('https://realitymix.cz/detail-projektu/nahled/nahled-%d.html', $addProjectResponse->output->developer_id)]);
		}
		return $response;
	}

	/**
	 * Odstraní nabídku ze vzdáleného serveru.
	 *
	 * @param array $projectData      Data projektu ve formátu iRest 1.
	 * @param array $additionalParams Specifická data pro daný export.
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru.
	 */
	public function deleteProject(array $projectData, array $additionalParams = array())
	{
		$response =  $this->_backend->delDevel($this->_sessionId, null, $projectData['kod']);
		return new Dalten_Export_Api_ServerResponse(
			$response->status == 200,
			$response->status,
			$response->statusMessage,
			$response->output
		);
	}

	/**
	 * Implementace interface.
	 *
	 * @throws BadMethodCallException
	 */
	public function getListingsList()
	{
		throw new BadMethodCallException("Method 'getListingsList' IS NOT implemented yet.");
	}

	/**
	 * Vždy uspěje.
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru.
	 */
	public function closeConnection()
	{
		return new Dalten_Export_Api_ServerResponse(true);
	}

	/**
	 * Pomocná metoda, která spravuje export fotografií k nabídce i k projektu.
	 *
	 * Fotografie jsou vyexportovány pouze v případě že jsou jiné (jak do obsahu tak i do pořadí)
	 * než na serveru.
	 *
	 * @param string $itemCode      Kód položky, ke které přidáváme obrázky.
	 * @param array  $images        Pole fotografií ve formátu iRest 1.
	 * @param string $itemType      Typ položky ke které přidáváme fotky (jedna z konstant EXPORT_*_IMAGES).
	 * @param bool   $forceReexport Vynutit export fotek?
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru, jestli se export podařil nebo co selhalo.
	 */
	private function _processImageUpdate($itemCode, array $images, $itemType, $forceReexport=false)
	{
		if ($itemType === self::EXPORT_LISTING_IMAGES) {
			$addMethodName = 'addPhoto';
			$listMethodName = 'listPhoto';
			$delMethodName = 'delPhoto';
		} elseif ($itemType === self::EXPORT_PROJECT_IMAGES) {
			$addMethodName = 'addDevelPhoto';
			$listMethodName = 'listDevelPhoto';
			$delMethodName = 'delDevelPhoto';
		} else {
			return new Dalten_Export_Api_ServerResponse(false, 0, 'Fotografie se nepodařilo vyexportovat.');
		}

		$listImageResponse = $this->_backend->$listMethodName($this->_sessionId, null, $itemCode);

		$remoteImages = array();
		if (isset($listImageResponse->output)) {
			$remoteImages = $listImageResponse->output->toArray();
		}
		if ($this->_comparePhotos($images, $remoteImages) && !$forceReexport) {
			return new Dalten_Export_Api_ServerResponse(true, 200, 'Fotografie beze změny');
		} else {
			// Pokud se fotky změnily, tak je všechny smažeme a nahrajeme znovu
			foreach ($listImageResponse->output as $remoteImage) {
				$delPhotoResult = $this->_backend->$delMethodName($this->_sessionId, $remoteImage['photo_id'], null);
				if ($delPhotoResult->status != 200) {
					return new Dalten_Export_Api_ServerResponse(false, 500, sprintf('Nepodařilo se smazat fotografii %s', $remoteImage['photo_id']));
				}
			}
		}

		$exported = 0;

		$success = true;
		$status = 200;
		$message = empty($images) ? '' : "Fotografie: \n";
		foreach (array_values($images) as $i => $image) {
			$file = realpath($image['soubor']);
			if ($file) {
				$response = $this->_backend->$addMethodName(
					$this->_sessionId,
					'',
					$itemCode,
					file_get_contents($file),
					!$i,
					$image['popis'],
					$image['id'],
					''
				);

				$status = $response->status;
				$message .= "{$image['soubor']} - $response->statusMessage\n";

				if ($status == 200) {
					$exported = $exported + 1;
				}

				if ($status != 200) {
					$success = false;
				}
			} else {
				return new Dalten_Export_Api_ServerResponse(false, 500, sprintf('Nenalezena fotka č. %d (%s)', $i, $file));
			}
		}

		if (count($images) != $exported) {
			return new Dalten_Export_Api_ServerResponse(false, 500, sprintf('Bohužel se nepodařilo vyexportovat %d z %d fotografií. Proveďte znovu reexport nabídky.', (count($images)-$exported), count($images) ));
		}

		return new Dalten_Export_Api_ServerResponse($success, $status, $message);
	}

	/**
	 * Porovná obrázky, přiložené k fotce, s obrázky, které jsou již nahrány na serveru srealit.
	 *
	 * @param array $localImages  Pole informací o fotkách nabídky ve formátu iRest1.
	 * @param array $remoteImages Pole informací o fotkách nabídky ve formátu výsledku metody listPhoto.
	 *
	 * @return bool Jsou fotky stejné?
	 */
	private function _comparePhotos(array $localImages, array $remoteImages)
	{
		if (count($localImages) != count($remoteImages)) {
			return false;
		}

		$localImages = array_values($localImages);

		$indexedListingImages = array();
		foreach ($localImages as $listingImage) {
			if (isset($listingImage['poradi'])) {
				$indexedListingImages[$listingImage['poradi']] = $listingImage;
			} else {
				// pokud někde chybí pořadí, nebudeme podle něj řadit :)
				$indexedListingImages = $localImages;
				break;
			}
		}
		ksort($indexedListingImages);
		$localImages = array_values($indexedListingImages);
		$remoteImages = array_values($remoteImages);

		foreach ($localImages as $index => $image) {
			if (empty($remoteImages[$index])) {
				return false;
			}
			if ($image['id'] != $remoteImages[$index]['photo_rkid']) {
				return false;
			}
		}

		return true;
	}

	/**
	 * Vypíše statistiky.
	 *
	 * @param string $advertId ID nabídky
	 * @param string $rkId     Vlastní ID nabídky.
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru.
	 */
	public function listStat($advertId, $rkId)
	{
		$response = $this->_backend->listStat($this->_sessionId, $advertId, $rkId);

		return new Dalten_Export_Api_ServerResponse(
			$response->status == 200,
			$response->status,
			$response->statusMessage,
			$response->output
		);
	}

	/**
	 * Vypíše statistiky.
	 *
	 * @param array $advertId Pole ID nabídky
	 * @param array $rkId     Pole vlastních ID nabídky.
	 *
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru.
	 */
	public function listStatMultiple(array $advertId, array $rkId)
	{
		$response = $this->_backend->listStatMultiple($this->_sessionId, $advertId, $rkId);

		return new Dalten_Export_Api_ServerResponse(
			$response->status == 200,
			$response->status,
			$response->statusMessage,
			$response->output
		);


		/*	Výstup:
			{
				'stats':
				[
					{
						'advert_id': '123',
						'rk_id': 'N123',
						'list_total': 53,
						'list_yesterday': 22,
						'detail_total': 44,
						'detail_yesterday': 11
					},
					...
				]
				'errors': [ 'nabídka s ID x nebyla nalezena', ...]
			}
		 */
	}

	/**
	 * Vytopuje nemovitost.
	 *
	 * @param array $listingData      Data nemovitosti.
	 * @param array $additionalParams Další parametry (nepoužívá se).
	 *
	 * @return Dalten_Export_Api_ServerResponseVerifiable Odpověď serveru.
	 */
	public function topListing(array $listingData, array $additionalParams = array())
	{
		$response = $this->_backend->topAdvert(
			$this->_sessionId,
			null,
			isset($listingData['kod']) ? $listingData['kod'] : null
		);

		return new Dalten_Export_Api_ServerResponse(
			$response->status == 200,
			$response->status,
			$response->statusMessage
		);
	}

	/** @inheritDoc */
	public function listListings()
	{
		$response = $this->_backend->listAdvert(
			$this->_sessionId
		);

		return new Dalten_Export_Api_ServerResponse(
			$response->status == 200,
			$response->status,
			$response->statusMessage,
			$response->output
		);
	}

	/**
	 * Výpis celých zpráv, ze všech inzerátu, odeslaných na RK v zadané datum.
	 *
	 * @param string $date Datum, kterého se statistika týká.
	 * @return Dalten_Export_Api_ServerResponse Odpověď serveru.
	 */
	public function listFullInquiry($date)
	{
		$response = $this->_backend->listFullInquiry(
			$this->_sessionId,
			$date
		);
		return new Dalten_Export_Api_ServerResponse(
			$response->status == 200,
			$response->status,
			$response->statusMessage,
			$response->output
		);
	}


}
