<?php

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

use idoit\Component\Helper\Unserialize;
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 isys_application;
use isys_callback;
use isys_cmdb_dao_category;
use isys_format_json;
use isys_tenantsettings;

/**
 * Class DialogDataType
 *
 * @package idoit\Module\Cmdb\Component\CategoryChanges\Type
 */
class DialogDataType extends AbstractType implements TypeInterface
{
    /**
     * @param Property $property
     * @param string   $tag
     *
     * @return bool
     */
    public function isApplicable(Property $property, string $tag)
    {
        $params = $property->getUi()->getParams();
        return $property->getInfo()->getType() === Property::C__PROPERTY__INFO__TYPE__DIALOG && is_array($params) && isset($params['p_arData']);
    }

    /**
     * @param string                 $tag
     * @param isys_cmdb_dao_category $dao
     * @param RequestData            $requestDataProvider
     * @param SmartyData             $smartyDataProvider
     * @param array                  $currentData
     * @param array                  $propertiesAlwaysInLogbook
     *
     * @return array
     * @throws \idoit\Exception\JsonException
     */
    public function handlePostData(
        string $tag,
        isys_cmdb_dao_category $dao,
        RequestData $requestDataProvider,
        SmartyData $smartyDataProvider,
        array $currentData = [],
        array $propertiesAlwaysInLogbook = []
    ) {
        $requestData = $requestDataProvider->getData();
        $smartyData = $smartyDataProvider->getData();
        $property = $this->getProperty();
        $uiField = $property->getUi()->getId();
        $currentObjectId = $dao->get_object_id();
        $currentPropertyTag = $this->getCurrentPropertyTag($dao, $tag);

        if (!isset($smartyData[$uiField])) {
            return [];
        }

        $newValueId = trim($requestData[$uiField]);
        $oldValueId = trim($smartyData[$uiField]['p_strSelectedID']);
        $rawData = $smartyData[$uiField]['p_arData'] ?? [];

        if (empty($rawData) || $newValueId === $oldValueId || ($newValueId === '' && $oldValueId == -1) || ($oldValueId === '' && $newValueId == -1)) {
            return [];
        }

        return $this->dataHandlerHelper($currentObjectId, $currentPropertyTag, $rawData, $oldValueId, $newValueId);
    }

    /**
     * @param $currentObjectId
     * @param $currentPropertyTag
     * @param $arData
     * @param $oldValueId
     * @param $newValueId
     *
     * @return array
     * @throws \idoit\Exception\JsonException
     */
    private function dataHandlerHelper($currentObjectId, $currentPropertyTag, $arData, $oldValueId, $newValueId)
    {
        $newValue = $oldValue = isys_tenantsettings::get('gui.empty_value', '-');

        if (is_string($arData)) {
            $data = isys_format_json::is_json_array($arData)
                ? isys_format_json::decode($arData)
                : Unserialize::toArray($arData);
        } elseif ($arData instanceof isys_callback) {
            $data = $arData->execute();
        } else {
            $data = $arData;
        }
        $lang = isys_application::instance()->container->get('language');

        if ($oldValueId >= 0 || $oldValueId !== '') {
            $oldValue = $lang->get($data[$oldValueId]);
        }

        if ($newValueId >= 0 || $newValueId !== '') {
            $newValue = $lang->get($data[$newValueId]);
        }

        $changes = ChangesData::factory(
            [
                $currentPropertyTag => [
                    self::CHANGES_FROM => $oldValue,
                    self::CHANGES_TO =>  $newValue
                ]
            ],
            $currentObjectId
        );

        return [
            self::CHANGES_CURRENT => $changes,
            self::CHANGES_TO => $changes,
        ];
    }

    /**
     * @param string                 $tag
     * @param isys_cmdb_dao_category $dao
     * @param DefaultData $currentDataProvider
     * @param DefaultData $changedDataProvider
     * @param array                  $propertiesAlwaysInLogbook
     *
     * @return array|void
     */
    public function handleData(
        string $tag,
        isys_cmdb_dao_category $dao,
        DefaultData $currentDataProvider,
        DefaultData $changedDataProvider,
        array $propertiesAlwaysInLogbook = []
    ) {
        $changedData = $changedDataProvider->getData();
        $currentData = $currentDataProvider->getData();
        $property = $this->getProperty();
        $arData = $property->getUi()->getParams()['p_arData'] ?? [];
        $currentObjectId = $dao->get_object_id();
        $currentPropertyTag = $this->getCurrentPropertyTag($dao, $tag);
        $newValueId = $changedData[$tag];
        $oldValueId = $currentData[$tag];

        if (empty($arData) || $newValueId === $oldValueId || ($newValueId === null && $oldValueId == -1) || ($oldValueId === null && $newValueId == -1)) {
            return [];
        }

        return $this->dataHandlerHelper($currentObjectId, $currentPropertyTag, $arData, $oldValueId, $newValueId);
    }

    /**
     * @param string                 $tag
     * @param isys_cmdb_dao_category $dao
     *
     * @return ChangesData|null
     */
    public function getChangesWithDefaults(string $tag, isys_cmdb_dao_category $dao)
    {
        $property = $this->getProperty();
        $defaultValue =$property->getUi()->getDefault();
        $rawData = $property->getUi()->getParams()['p_arData'] ?? [];
        $currentObjectId = $dao->get_object_id();
        $currentPropertyTag = $this->getCurrentPropertyTag($dao, $tag);
        $emptyState = isys_tenantsettings::get('gui.empty_value', '-');

        if (is_string($rawData)) {
            $data = isys_format_json::is_json_array($rawData)
                ? isys_format_json::decode($rawData)
                : Unserialize::toArray($rawData);
        } elseif ($rawData instanceof isys_callback) {
            $data = $rawData->execute();
        } else {
            $data = $rawData;
        }

        $defaultValue = $data[$defaultValue] ?? $emptyState;

        return ChangesData::factory(
            [
                $currentPropertyTag => [
                    self::CHANGES_FROM => $emptyState,
                    self::CHANGES_TO => $defaultValue
                ]
            ],
            $currentObjectId
        );
    }
}
