<?php

namespace idoit\Module\Cmdb\Component\CategoryChanges\Type\Browser;

use idoit\Component\Property\Property;
use idoit\Module\Cmdb\Component\CategoryChanges\Data\ChangesData;
use idoit\Module\Cmdb\Component\CategoryChanges\Data\DefaultData;
use idoit\Module\Cmdb\Component\CategoryChanges\Data\RequestData;
use idoit\Module\Cmdb\Component\CategoryChanges\Data\SmartyData;
use idoit\Module\Cmdb\Component\CategoryChanges\Type\TypeInterface;
use isys_application;
use isys_cmdb_dao_cable_connection;
use isys_cmdb_dao_category;
use isys_cmdb_dao_category_g_connector;
use isys_tenantsettings;

/**
 * Class ConnectorBrowserType
 *
 * @package idoit\Module\Cmdb\Component\CategoryChanges\Type\Browser
 */
class ConnectorBrowserType extends AbstractBrowserType implements TypeInterface, ObjectBrowserTypeInterface
{
    /**
     * @param Property $property
     * @param string   $tag
     *
     * @return bool
     */
    public function isApplicable(Property $property, string $tag)
    {
        return $property->getInfo()->getType() === Property::C__PROPERTY__INFO__TYPE__OBJECT_BROWSER &&
            $property->getUi()->getParams()['p_strPopupType'] === 'browser_cable_connection_ng';
    }

    /**
     * @param string                 $tag
     * @param isys_cmdb_dao_category $dao
     * @param RequestData            $requestDataProvider
     * @param SmartyData             $smartyDataProvider
     * @param array                  $currentData
     *
     * @return array
     */
    public function handlePostData(string $tag, isys_cmdb_dao_category $dao, RequestData $requestDataProvider, SmartyData $smartyDataProvider, array $currentData = [])
    {
        $cableConnectionDao = isys_cmdb_dao_category_g_connector::instance(isys_application::instance()->container->get('database'));
        $requestData = $requestDataProvider->getData();
        $smartyData = $smartyDataProvider->getData();
        $property = $this->getProperty();
        $currentObjectId = $dao->get_object_id();
        $currentPropertyTag = $this->getCurrentPropertyTag($dao, $tag);
        $uiField = $property->getUi()->getId();
        $uiHiddenField = $uiField . '__HIDDEN';
        $newValue = $oldValue = $changes = [];

        $currentEntryId = $requestData[C__GET__ID];
        $oldValueOutput = $newValueOutput = isys_tenantsettings::get('gui.empty_value', '-');
        $separator = isys_tenantsettings::get('gui.separator.connector', ' > ');
        $this->setBackwardPropertyTag($property->getInfo()->getBackwardProperty() ?: null);
        $linkedProperty = $property->getInfo()->getLinkedProperty() ?? null;
        $currentEntry = [];

        if ($linkedProperty) {
            [$linkedPropertyClass, $linkedPropertyTag] = explode('::', $linkedProperty);
        }

        $newValueId = (int)$requestData[$uiHiddenField];
        $oldValueId = (int)($smartyData[$uiField]['p_strSelectedID'] ?:
            (is_numeric($smartyData[$uiField]['p_strValue']) ? $smartyData[$uiField]['p_strValue']: null));

        if ($newValueId === 0 && $oldValueId === 0) {
            return [];
        }

        if ($currentEntryId) {
            $currentEntry = $cableConnectionDao->getConnectorNameByConnectorId($currentEntryId, false);
            if ($linkedProperty !== null && isset($linkedPropertyTag) && !empty($currentEntry)) {
                $currentChanges[self::CHANGES_CURRENT][] = ChangesData::factory(
                    $this->setChanges($linkedProperty, $currentEntry['connector'], $currentEntry['connector']),
                    $dao->get_object_id()
                );
            }
        }

        if ($newValueId === $oldValueId && $this->getBackwardPropertyTag() !== null) {
            $connectorData = $cableConnectionDao->getConnectorNameByConnectorId($newValueId, false);

            if ($linkedProperty !== null && isset($linkedPropertyTag) && !empty($currentEntry)) {
                $changes[self::CHANGES_TO][] = ChangesData::factory(
                    $this->setChanges($linkedProperty, $currentEntry['connector'], $currentEntry['connector']),
                    $connectorData['objID']
                );
            }

            $this->setToObjectId($connectorData['objID']);
            $changes[self::CHANGES_TO][] = $this->handlePostDataHelper($dao, $connectorData['objID'], $connectorData, [], self::CHANGES_BOTH);
            return $changes;
        }

        if ($oldValueId > 0 &&
            $oldValueId !== $newValueId &&
            $this->getBackwardPropertyTag() !== null
        ) {
            $connectorData = $cableConnectionDao->getConnectorNameByConnectorId($oldValueId, false);

            if ($linkedProperty !== null && isset($linkedPropertyTag)) {
                $changes[self::CHANGES_FROM][] = ChangesData::factory(
                    $this->setChanges($linkedProperty, $connectorData['connector'], $connectorData['connector']),
                    $connectorData['objID']
                );
            }

            $changes[self::CHANGES_FROM][] = $this->handlePostDataHelper($dao, $connectorData['objID'], $connectorData, $currentEntry, self::CHANGES_FROM);
            $this->setFromObjectId($connectorData['objID']);
            unset($connectorData['id'], $connectorData['objID'], $connectorData['type'], $connectorData['connectorID']);
            $oldValueOutput = implode($separator, $connectorData);
        }

        if ($newValueId > 0 &&
            $newValueId !== $oldValueId
        ) {
            $connectorData = $cableConnectionDao->getConnectorNameByConnectorId($newValueId, false);
            $oldConnectorData = $cableConnectionDao->getAssignedObjectByConnectorId($newValue['connectorID'])->get_row() ?? $oldValue;

            if ($linkedProperty !== null && isset($linkedPropertyTag)) {
                $changes[self::CHANGES_TO][] = ChangesData::factory(
                    $this->setChanges($linkedProperty, $connectorData['connector'], $connectorData['connector']),
                    $connectorData['objID']
                );
            }

            $changes[self::CHANGES_TO][] = $this->handlePostDataHelper($dao, $connectorData['objID'], $currentEntry, $oldConnectorData, self::CHANGES_TO);
            $this->setToObjectId($connectorData['objID']);
            unset($connectorData['id'], $connectorData['objID'], $connectorData['type'], $connectorData['connectorID']);
            $newValueOutput = implode($separator, $connectorData);
        }

        $currentChanges[self::CHANGES_CURRENT][] =
            ChangesData::factory(
                [
                    $currentPropertyTag => [
                        self::CHANGES_FROM => $oldValueOutput,
                        self::CHANGES_TO   => $newValueOutput
                    ]
                ],
                $dao->get_object_id()
            );

        $changes =  array_merge($currentChanges, $changes);

        return $changes;
    }

    /**
     * @param isys_cmdb_dao_category $dao
     * @param int                    $referenceId
     * @param array                  $connectorData
     * @param array|null             $oldConnectorData
     * @param string                 $direction
     *
     * @return ChangesData
     */
    private function handlePostDataHelper(isys_cmdb_dao_category $dao, int $referenceId, array $connectorData, ?array $oldConnectorData = [], $direction = self::CHANGES_FROM)
    {
        $backwardProperty = $this->getProperty()->getInfo()->getBackwardProperty();
        $separator = isys_tenantsettings::get('gui.separator.connector', ' > ');
        $emptyValue = isys_tenantsettings::get('gui.empty_value', '-');
        $changes = [];
        $outputOld = $outputNew = $emptyValue;

        if (!empty($connectorData)) {
            unset($connectorData['id'], $connectorData['objID'], $connectorData['type'], $connectorData['connectorID']);
            $outputNew = implode($separator, $connectorData);
        }

        if (!empty($oldConnectorData)) {
            unset($oldConnectorData['id'], $oldConnectorData['objID'], $oldConnectorData['type'], $oldConnectorData['connectorID']);
            $outputOld = implode($separator, $oldConnectorData);
        }

        switch ($direction) {
            case self::CHANGES_FROM:
                $changes = $this->setChanges(
                    $backwardProperty,
                    $outputOld,
                    $this->getLanguage()->get('LC__UNIVERSAL__CONNECTION_DETACHED')
                );
                break;
            case self::CHANGES_TO:
                $changes = $this->setChanges(
                    $backwardProperty,
                    $emptyValue,
                    $outputNew
                );
                break;
            case self::CHANGES_BOTH:
                $changes = $this->setChanges(
                    $backwardProperty,
                    $outputNew,
                    $outputNew
                );
                break;
        }

        return ChangesData::factory($changes, $referenceId);
    }

    /**
     * @param DefaultData $currentData
     * @param DefaultData $changedData
     *
     * @return array
     */
    public function handleData(DefaultData $currentData, DefaultData $changedData)
    {
        // TODO: Implement handleData() method.
    }

    public function handleRanking()
    {
        // TODO: Implement handleRanking() method.
    }
}
