<?php
// Copyright (c) Pickware GmbH. All rights reserved.
// This file is part of software that is released under a proprietary license.
// You must not copy, modify, distribute, make publicly available, or execute
// its contents or parts thereof without express permission by the copyright
// holder, unless otherwise permitted by law.

namespace Shopware\Plugins\ViisonPickwareCommon\Subscribers\Backend;

use Shopware\Models\Article\Detail as ArticleDetail;
use Shopware\Plugins\ViisonCommon\Classes\Subscribers\Base;
use Shopware\CustomModels\ViisonPickwareERP\ItemProperty\ArticleDetailItemProperty;
use Shopware\CustomModels\ViisonPickwareERP\ItemProperty\ItemProperty;

class Article extends Base
{
    /**
     * @inheritdoc
     */
    public static function getSubscribedEvents()
    {
        return [
            'Shopware_Controllers_Backend_Article::getArticleData::after' => 'onAfterGetArticleData',
            'Shopware_Controllers_Backend_Article::detailListAction::after' => 'onAfterDetailListAction',
            'Shopware_Controllers_Backend_Article::saveAction::after' => 'onAfterSaveAction',
            'Shopware_Controllers_Backend_Article::saveDetailAction::after' => 'onAfterSaveDetailAction',
        ];
    }

    /**
     * Adds the custom article detail fields to the response data.
     *
     * @param \Enlight_Hook_HookArgs $args
     */
    public function onAfterGetArticleData(\Enlight_Hook_HookArgs $args)
    {
        $data = $args->getReturn();
        $this->addCustomArticleDetailData($data[0]['mainDetail']);
        $args->setReturn($data);
    }

    /**
     * Adds the custom article detail fields to the response data.
     *
     * @param \Enlight_Hook_HookArgs $args
     */
    public function onAfterDetailListAction(\Enlight_Hook_HookArgs $args)
    {
        $view = $args->getSubject()->View();
        $data = $view->data;
        if (is_array($data)) {
            foreach ($data as &$detail) {
                $this->addCustomArticleDetailData($detail);
            }
        }
        $view->data = $data;
    }

    /**
     * Saves the custom article detail fields, in case the main action succeeded, and adds the updated custom fields to
     * the response data.
     *
     * @param \Enlight_Hook_HookArgs $args
     */
    public function onAfterSaveAction(\Enlight_Hook_HookArgs $args)
    {
        $view = $args->getSubject()->View();
        if (!$view->success) {
            return;
        }

        $responseData = $view->data;
        $requestData = $args->getSubject()->Request()->getParams();
        if (array_key_exists('mainDetail', $requestData) && count($requestData['mainDetail']) >= 1) {
            $this->saveCustomArticleDetailData($responseData[0]['mainDetailId'], $requestData['mainDetail'][0]);
        }

        // Make sure to send the updated custom data
        $this->addCustomArticleDetailData($responseData[0]['mainDetail']);
        $view->data = $responseData;
    }

    /**
     * Saves the custom variant article detail fields, in case the main action succeeded, and adds the updated custom
     * fields to the response data.
     *
     * @param \Enlight_Hook_HookArgs $args
     */
    public function onAfterSaveDetailAction(\Enlight_Hook_HookArgs $args)
    {
        $view = $args->getSubject()->View();
        if (!$view->success) {
            return;
        }

        $requestParams = $args->getSubject()->Request()->getParams();
        $this->saveCustomArticleDetailData($requestParams['id'], $requestParams);
    }

    /**
     * @param int $detailId
     * @param array $detail
     */
    protected function saveCustomArticleDetailData($detailId, $detail)
    {
        $articleDetail = $this->get('models')->find(ArticleDetail::class, $detailId);
        if (!$articleDetail) {
            return;
        }

        if (isset($detail['pickwareItemProperties'])) {
            // Fetch all previously mapped property types
            $existingTypeMappings = $this->get('models')->getRepository(ArticleDetailItemProperty::class)->findBy([
                'articleDetail' => $articleDetail,
            ]);

            // Determine newly added type IDs and create respective mappings
            $mappedTypeIds = array_map(
                function (ArticleDetailItemProperty $mapping) {
                    return $mapping->getItemProperty()->getId();
                },
                $existingTypeMappings
            );
            $addedTypeIds = array_diff($detail['pickwareItemProperties'] ?: [], $mappedTypeIds);
            $newTypeMappings = [];
            foreach ($addedTypeIds as $typeId) {
                $type = $this->get('models')->find(ItemProperty::class, $typeId);
                if (!$type) {
                    continue;
                }
                $typeMapping = new ArticleDetailItemProperty($articleDetail, $type);
                $this->get('models')->persist($typeMapping);
                $newTypeMappings[] = $typeMapping;
            }
            $this->get('models')->flush($newTypeMappings);

            // Remove old mappings
            foreach ($existingTypeMappings as $typeMapping) {
                if (!in_array($typeMapping->getItemProperty()->getId(), $detail['pickwareItemProperties'] ?: [])) {
                    $this->get('models')->remove($typeMapping);
                    $this->get('models')->flush($typeMapping);
                }
            }
        }
    }

    /**
     * @param &array $articleDetailData
     */
    protected function addCustomArticleDetailData(&$articleDetailData)
    {
        // Fetch the IDs of all mapped property types
        $typeMappings = $this->get('models')->getRepository(ArticleDetailItemProperty::class)->findBy([
            'articleDetailId' => $articleDetailData['id'],
        ]);
        $articleDetailData['pickwareItemProperties'] = array_map(
            function (ArticleDetailItemProperty $mapping) {
                return $mapping->getItemProperty()->getId();
            },
            $typeMappings
        );
    }
}
